淺入淺出實現一個異步求和函數

簡化:兩數之和

咱們先來簡單的實現一個異步兩數之和函數前端

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
複製代碼

加深:多數之和

上面咱們實現了兩數之和,而後擴展到多數之和喃?git

提到數組求和問題,咱們首先想到的是 reducegithub

reduce() 方法對數組中的每一個元素執行一個由您提供的reducer函數(升序執行),將其結果彙總爲單個返回值。面試

—— MDN算法

arr.reduce(callback(acc, cur[, idx[, arr]])[, initialValue])
複製代碼

callback 函數接收4個參數:數組

  • acc :累計器
  • cur :當前值
  • idx : 當前索引
  • arr :源數組

其中, initialValue 可選,markdown

  • 若是有 initialValueacc 取值爲 initialValuecur 取數組中的第一個值
  • 若是沒有:acc 取數組中的第一個值, cur 取數組中的第二個值
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
複製代碼

關於本題:來自@champkeh異步

設置初始值爲 Promise.resolve(0) ,經歷 5 次求和:async

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,串行異步求和,這顯然不是最優的

優化:使用 Promise.all

咱們能夠兩兩一組,使用 Promise.all 求和,再把和兩兩一組繼續求和…..,知道只剩餘一個就是最終的結果

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 組內求和
    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")
複製代碼

天天三分鐘,進階一個前端小 tip 面試題庫 算法題庫

相關文章
相關標籤/搜索