背景
前几天有幸参加了我梦寐已久的公司的技术三面,其中一道题目想和大家分享下
题目
有一个asyncSum函数可以异步求两数之和,请实现一个sum函数,实现求和功能
// 类似这种,通过asyncSum函数异步拿到两数之和
function asyncSum(a, b, cb) {
setTimeout(() => {
cb(a + b)
})
}
const res1 = await sum(1,2,3,4)
const res2 = await sum(1,2,3,4,5,6)
分析
1.最好将asyncSum这种类似node callback调用的方式,转换成Promise(好处:可以利用async await写出类似同步代码,使代码阅读性更高)
const asyncSumPromise = (a, b) => {
if (a === 0) return Promise.resolve(b);
if (b === 0) return Promise.resolve(a);
return new Promise((resolve) => {
asyncSum(a, b, resolve)
});
};
其实还能加上根据参数,缓存结果
- 拿到所有入参,两个两个调用
asyncSumPromise,然后利用Promise.all处理,得到结果,然后递归调用sum
const sum = async (...args) => {
// 终止递归
if (args.length <= 2) return asyncSumPromise(args[0] || 0, args[1] || 0);
const len = args.length;
let i = 0;
let taskList = [];
// 初始化任务
while (i < len) {
taskList.push(asyncSumPromise(args[i], args[i + 1] || 0));
i += 2;
}
const res = await Promise.all(taskList);
// 递归求和
return sum(...res);
};
新挑战
当我开开心心的写完后,面试官又说,如果现在出现一种场景,假设我某次调用asyncSum很慢,然后你又使用了Promise.all,这就会导致所有的都堵塞住,请问有什么办法能解决这种场景吗?
再次分析
出现这种场景的原因是Promise.all的特性导致的(需要所有Promise都resolve才行),那其实可以使用Promise.race,每当完成两个后,然后迭代的继续求和,此时就解决了这个场景。
const sum = async (...args) => {
if (args.length <= 2) return asyncSumPromise(args[0] || 0, args[1] || 0);
const len = args.length;
let i = 0;
let taskList = [];
// 初始化任务
while (i < len) {
// 注意:这里需要保存一下值的引用
let pushIndex = i >> 1;
taskList.push(
// 注意:这里需要记录,当前的Promise的索引,用于完成后清除
asyncSumPromise(args[i], args[i + 1] || 0).then((v) => [v, pushIndex])
);
i += 2;
}
// 清除完成的
const clearComplete = (completeIndex) => {
taskList = taskList.map((item, listIndex) =>
// 注意:这里需要做一个索引的变动
listIndex > completeIndex ? item.then(([v, i]) => [v, i - 1]) : item
);
taskList.splice(completeIndex, 1);
};
// 得到最快的
const handle = async () => {
const [v, index] = await Promise.race(taskList);
clearComplete(index);
return v;
};
// 处理最快两个
while (taskList.length) {
const v1 = await handle();
// 任务清空完
if (taskList.length === 0) return v1;
const v2 = await handle();
taskList.push(
asyncSumPromise(v1, v2).then((v) => [v, taskList.length - 1])
);
}
};
哈哈哈,题目就解决了
最后
很荣幸能有这次面试机会,去认清楚自己的不足。
也祝各位小伙伴们,能早日拿到自己心仪Offer。各位面试失败的小伙伴们也不要气馁,毕竟失败总是贯穿人生的,早日重拾信心,加油,你是最棒的,哈哈哈。