Skip to content

不使用加号 + 实现异步相加函数 #57

@Inchill

Description

@Inchill

不使用加号 + 实现异步相加函数

题目描述

给定一个辅助函数如下:

function asyncAdd(a, b, callback) {
    setTimeout(function() {
        callback(a + b)
    }, 1000)
}

在不使用加号 + 的情况下,实现一个函数,实现两个异步相加,返回一个异步结果。示例如下:

sum(1,2,3,4,5,6,7,8,9,10,11).then(sum => console.log(sum))

思路

先说下整体思路,不能使用加号的话,那就只能借助辅助函数来完成运算。因为最终返回的是 Promise,所以一开始想到的就是需要对辅助函数进行包装,使得从语言层面能异步控制它。接下来就是对参数个数进行分析,理想状态下就是对参数不停地进行二分操作,降低时间复杂度,将其变为 O(log n) 就是最佳时间。在二分地过程中,涉及到递归,递归终止条件就是只有一个参数,这时候就可以直接返回。如果是还剩 2 个参数,调用包装过的辅助函数,返回一个 Promise,然后通过 then 链式调用,将结果返回。

代码实现

function asyncAdd(a = 0, b = 0, callback) {
    setTimeout(function() {
        callback(a + b)
    }, 1000)
}

const add = (a = 0, b = 0) => new Promise((resolve) => asyncAdd(a, b, resolve));

function sum(...args) {
    if (args.length === 1) return new Promise((resolve) => resolve(args));
    if (args.length === 2) {
        return new Promise((resolve) => asyncAdd(args[0], args[1], resolve));
    }

    let params = [];
    for (let i = 0; i < args.length; i += 2) {
        if (i + 1 < args.length) {
            params.push([args[i], args[i + 1]]);
        } else {
            params.push([args[i]]);
        }
    }

    let fns = []

    params.forEach(([a, b]) => {
        fns.push(add(a, b));
    });

    return Promise.allSettled(fns).then((res) => {
        const answers = res.map(item => item.value);
        console.log(answers)
        return sum(...answers);
    })
}

测试

const start = Date.now();
sum(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25).then(sum => {
    const end = Date.now()
    console.log('sum =', sum)
    console.log(`time = ${(end - start) / 1000}s`)
})

// [
//    3,  7, 11, 15, 19, 23,
//   27, 31, 35, 39, 43, 47,
//   25
// ]
// [
//   10, 26, 42, 58,
//   74, 90, 25
// ]
// [ 36, 100, 164, 25 ]
// [ 136, 189 ]
// sum = 325
// time = 5.018s

可以看到,在时间上并不是串行的 25 秒,而是 5 秒,极大地提升了运算速度。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions