一道字節(jié)筆試題,實(shí)現(xiàn)一個(gè)異步求和函數(shù)
題目:
提供一個(gè)異步 add 方法如下,需要實(shí)現(xiàn)一個(gè) await sum(...args) 函數(shù):
function asyncAdd(a, b, callback) {
setTimeout(function () {
callback(null, a + b);
}, 1000);
}
簡(jiǎn)化:兩數(shù)之和
我們先來(lái)簡(jiǎn)單的實(shí)現(xiàn)一個(gè)異步兩數(shù)之和函數(shù)
function sumT(a, b) {
return await new Promise((resolve, reject) => {
asyncAdd(a, b, (err, res) => {
if(!err) {
resolve(res)
}
reject(err)
})
})
}
// 測(cè)試
const test = await sumT(1, 2)
console.log(test)
// 3
加深:多數(shù)之和
上面我們實(shí)現(xiàn)了兩數(shù)之和,然后擴(kuò)展到多數(shù)之和喃?
提到數(shù)組求和問(wèn)題,我們首先想到的是 reduce
reduce()方法對(duì)數(shù)組中的每個(gè)元素執(zhí)行一個(gè)由您提供的reducer函數(shù)(升序執(zhí)行),將其結(jié)果匯總為單個(gè)返回值。—— MDN
arr.reduce(callback(acc, cur[, idx[, arr]])[, initialValue])
callback 函數(shù)接收4個(gè)參數(shù):
acc:累計(jì)器cur:當(dāng)前值idx:當(dāng)前索引arr:源數(shù)組
其中, initialValue 可選,
如果有 initialValue:acc取值為initialValue,cur取數(shù)組中的第一個(gè)值如果沒(méi)有: acc取數(shù)組中的第一個(gè)值,cur取數(shù)組中的第二個(gè)值
const arr = [1, 2, 3, 4];
const reducer = (acc, cur) => acc + cur;
// 1 + 2 + 3 + 4
console.log(arr.reduce(reducer));
// 輸出: 10
// 5 + 1 + 2 + 3 + 4
console.log(arr.reduce(reducer, 5));
// 輸出: 15
關(guān)于本題:來(lái)自@champkeh
設(shè)置初始值為 Promise.resolve(0) ,經(jīng)歷 5 次求和:
function sum(...args) {
return new Promise(resolve => {
args.reduce((acc, cur) => acc.then(total => sumT(total, cur)), Promise.resolve(0)).then(resolve)
})
}
// 測(cè)試
await sum(1, 2, 3, 4, 5)
// 15
但這存在一個(gè)耗時(shí)較長(zhǎng)的問(wèn)題,我們可以計(jì)算下時(shí)間:
console.time("sum")
// 測(cè)試
await sum(1, 2, 3, 4, 5)
// 15
console.timeEnd("sum")

也就是說(shuō),我們每次求和都會(huì)花費(fèi) 1s,串行異步求和,這顯然不是最優(yōu)的
優(yōu)化:使用 Promise.all
我們可以?xún)蓛梢唤M,使用 Promise.all 求和,再把和兩兩一組繼續(xù)求和…..,知道只剩余一個(gè)就是最終的結(jié)果
async function sum(...args) {
// 用于考察每次迭代的過(guò)程
console.log(args)
// 如果僅有一個(gè),直接返回
if(args.length === 1) return args[0]
let result = []
// 兩兩一組,如果有剩余一個(gè),直接進(jìn)入
for(let i = 0; i < args.length - 1; i+=2) {
result.push(sumT(args[i], args[i + 1]))
}
if(args.length%2) result.push(args[args.length-1])
// Promise.all 組內(nèi)求和
return sum(...await Promise.all(result))
}
// 測(cè)試
test = await sum(1, 2, 3, 4, 5)
// 15

console.time("sum")
await sum(1, 2, 3, 4, 5)
console.timeEnd("sum")

來(lái)自:https://github.com/Advanced-Frontend/Daily-Interview-Question
最后
評(píng)論
圖片
表情
