一道字節(jié)筆試題,實現(xiàn)一個異步求和函數(shù)
題目:
提供一個異步 add 方法如下,需要實現(xiàn)一個 await sum(...args) 函數(shù):
- function asyncAdd(a, b, callback) {
- setTimeout(function () {
- callback(null, a + b);
- }, 1000);
- }
簡化:兩數(shù)之和
我們先來簡單的實現(xiàn)一個異步兩數(shù)之和函數(shù)
- function sumT(a, b) {
- return await new Promise((resolve, reject) => {
- asyncAdd(a, b, (err, res) => {
- if(!err) {
- resolve(res)
- }
- reject(err)
- })
- })
- }
- // 測試
- const test = await sumT(1, 2)
- console.log(test)
- // 3
加深:多數(shù)之和
上面我們實現(xiàn)了兩數(shù)之和,然后擴展到多數(shù)之和喃?
提到數(shù)組求和問題,我們首先想到的是 reduce
reduce() 方法對數(shù)組中的每個元素執(zhí)行一個由您提供的reducer函數(shù)(升序執(zhí)行),將其結(jié)果匯總為單個返回值。
—— MDN
- arr.reduce(callback(acc, cur[, idx[, arr]])[, initialValue])
callback 函數(shù)接收4個參數(shù):
- acc :累計器
- cur :當前值
- idx :當前索引
- arr :源數(shù)組
其中, initialValue 可選,
- 如果有 initialValue :acc 取值為 initialValue , cur 取數(shù)組中的第一個值
- 如果沒有:acc 取數(shù)組中的第一個值, cur 取數(shù)組中的第二個值
- 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)于本題:來自@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)
- })
- }
- // 測試
- await sum(1, 2, 3, 4, 5)
- // 15
但這存在一個耗時較長的問題,我們可以計算下時間:
- console.time("sum")
- // 測試
- await sum(1, 2, 3, 4, 5)
- // 15
- console.timeEnd("sum")
也就是說,我們每次求和都會花費 1s,串行異步求和,這顯然不是最優(yōu)的
優(yōu)化:使用 Promise.all
我們可以兩兩一組,使用 Promise.all 求和,再把和兩兩一組繼續(xù)求和…..,知道只剩余一個就是最終的結(jié)果
- async function sum(...args) {
- // 用于考察每次迭代的過程
- console.log(args)
- // 如果僅有一個,直接返回
- if(args.length === 1) return args[0]
- let result = []
- // 兩兩一組,如果有剩余一個,直接進入
- 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))
- }
- // 測試
- test = await sum(1, 2, 3, 4, 5)
- // 15
- console.time("sum")
- await sum(1, 2, 3, 4, 5)
- console.timeEnd("sum")
來自:https://github.com/Advanced-Frontend/Daily-Interview-Question