第三十届|前端早早聊大会 BFF 专场 - 玩转先后端接口(GraphQL、统一网关、API 接入、API 管理、协议转换、统一安全切面、高并发处理、可视化编排、统一稳定性建设...)8-14 全天直播,9 位讲师,报名上车看直播👉 ):javascript
前端早早聊大会,与掘金联合举办。加 codingdreamer 进大会技术群,赢在新的起跑线, 全部往期都有全程录播,上手年票一次性解锁所有前端
本文是第二十二届 - 前端早早聊面试方法专场,也是早早聊第 157 场,来自盒马高级专家-宗羽 的分享。java
很普通的一道题git
// 假设本地机器没法作加减乘除运算,须要经过远程请求让服务端来实现。
// 以加法为例,现有远程API的模拟实现
const addRemote = async (a, b) => new Promise(resolve => {
setTimeout(() => resolve(a + b), 1000)
});
// 请实现本地的add方法,调用addRemote,能最优的实现输入数字的加法。
async function add(...inputs) {
// 你的实现
}
// 请用示例验证运行结果:
add(1, 2)
.then(result => {
console.log(result); // 3
});
add(3, 5, 2)
.then(result => {
console.log(result); // 10
})
复制代码
答案一 最基本的答案,若是写不出来,那大几率是经过不了了github
async function add(...args) {
let res = 0;
if (args.length <= 2) return res;
for (const item of args) {
res = await addRemote(res, item);
}
return res;
}
复制代码
递归版本web
async function add(...args) {
let res = 0;
if (args.length === 0) return res;
if (args.length === 1) return args[0];
const a = args.pop();
const b = args.pop();
args.push(await addRemote(a, b));
return add(...args);
}
复制代码
常见的问题:面试
答案二 有候选人的答案以下:算法
// Promise链式调用版本
async function add(...args) {
return args.reduce((promiseChain, item) => {
return promiseChain.then(res => {
return addRemote(res, item);
});
}, Promise.resolve(0));
}
复制代码
从这个实现能够看出:后端
这个版本至少能到 70 分数组
答案三 以前的答案结果都是对的,可是咱们把耗时打出来,能够看到耗时和参数个数成线性关系,由于全部计算都是串行的,显然不是最优的解
更好一点的答案:
function add(...args) {
if (args.length <= 1) return Promise.resolve(args[0])
const promiseList = []
for (let i = 0; i * 2 < args.length - 1; i++) {
const promise = addRemote(args[i * 2], args[i * 2 + 1])
promiseList.push(promise)
}
if (args.length % 2) {
const promise = Promise.resolve(args[args.length - 1])
promiseList.push(promise)
}
return Promise.all(promiseList).then(results => add(...results));
}
复制代码
能够看到很明显的优化。
答案四 还能再优化吗? 有些同窗会想到加本地缓存
const cache = {};
function addFn(a, b) {
const key1 = `${a}${b}`;
const key2 = `${b}${a}`;
const cacheVal = cache[key1] || cache[key2];
if (cacheVal) return Promise.resolve(cacheVal);
return addRemote(a, b, res => {
cache[key1] = res;
cache[key2] = res;
return res;
});
}
复制代码
加了缓存之后,咱们再第二次执行相同参数加法时,能够不用请求远端,直接变成毫秒级返回
还能再优化吗?交给你们去思考
有些时候会让候选人将代码提交到 Github 仓库,以工做中一个实际的模块标准来开发,能够考察:
实际题目
// 有一个 10G 文件,每一行是一个时间戳,
// 如今要在一台 2C4G 的机器上对它进行排序,输出排序之后的文件
// 案例输入
// 1570593273487
// 1570593273486
// 1570593273488
// …
// 输出
// 1570593273486
// 1570593273487
// 1570593273488
// …
复制代码
先看一个答案,看看哪里有问题
async function sort(inputFile, outputFile) {
const input = fs.createReadStream(inputFile);
const rl = readline.createInterface({ input });
const arr = [];
for await (const line of rl) {
const item = Number(line);
arr.push(item);
}
arr.sort((a, b) => a - b);
fs.writeFileSync(outputFile, arr.join('\n'));
}
复制代码
10GB 的文件没法一次性放进内存里处理,内存只有 4GB
再看一个神奇的答案,只有一行代码,并且从结果来讲是正确的。但不是咱们笔试想要的答案。
const cp = require('child_process');
function sort(inputFile, outputFile) {
cp.exec(`sort -n ${inputFile} > ${outputFile}`);
}
复制代码
解题思路
再将问题拆解
本题最难的点在于如何合并全部小文件。代码如何实现?
堆有一些特性:
咱们尝试把下面数组构形成一个最小堆
完整的实现参考:github.com/gxcsoccer/e…
「数据分析不是某个固定的职位,而是人工智能时代的通用能力」
第三十届|前端早早聊大会 BFF 专场 - 玩转先后端接口(GraphQL、统一网关、API 接入、API 管理、协议转换、统一安全切面、高并发处理、可视化编排、统一稳定性建设...)8-14 全天直播,9 位讲师,报名上车看直播👉 ):