异步加法

假设有一台本地机器,无法做加减乘除运算(包括位运算)。

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
26
27
28
// 假设有一台本地机器,无法做加减乘除运算(包括位运算)。
// 因此无法执行 a + b、a+ = 1 这样的 JS 代码。
// 然后我们提供一个服务器端的 HTTP API。
// 可以传两个数字类型的参数,响应结果是这两个参数的和。
// 这个 HTTP API 的 JS SDK(在本地机器上运行)​的使用方法如下:
// SDK 的模拟实现:
function asyncAdd(a, b, cb) {
setTimeout(() => {
cb(null, a + b);
}, Math.floor(Math.random() * 1000))
}

// SDK 模拟调用
asyncAdd(3, 5, (err, result) => {
console.log(result); // 8
});

async function sum(...args) {

}
// 现在要求在本地机器上实现一个 sum 函数,支持以下用法:
(async () => {
const result1 = await sum(1, 4, 6, 9, 2, 4);
const result2 = await sum(3, 4, 9, 2, 5, 3, 2, 1, 7);
const result3 = await sum(1, 6, 0, 5);
console.log([result1, result2, result3]); // [26, 36, 12]
})();
// 时间最优?

简化:两数之和

实现一个异步两数之和函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
async function sumT(a, b) {
return await new Promise((resolve, reject) => {
asyncAdd(a, b, (err, res) => {
if (!err) {
resolve(res)
}
reject(err)
})
})
}

(
async () => {
const test = await sumT(1, 2) // 3
}
)()

加深:多数之和

耗时较长,因为串行异步求和

1
2
3
4
5
6
7
8
9
10
11
12
13
function sum(...args) {
return new Promise(resolve => {
args.reduce((pre, cur) => pre.then(total => sumT(total, cur)), Promise.resolve(0)).then(resolve)
})
}

(
async () => {
console.time('sum')
const test = await sum(1, 2, 3, 4, 5) // 15
console.timeEnd('sum') // 5.010s
}
)()

优化:使用 Promise.all

两两一组,使用 Promise.all 求和,再把和两两一组继续求和…..,直到只剩余一个就是最终的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
async function sum(...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))
}

// 测试
(
async () => {
console.time('sum')
const test = await sum(1, 2, 3, 4, 5)
console.log(test) //15
console.timeEnd('sum') //3.013s
}
)()