如下为一段代码,请完善sum函数,使得 sum(1,2,3,4,5,6) 函数返回值为 21 ,需要在 sum 函数中调用 asyncAdd 函数进行数值运算,且不能修改asyncAdd函数
题目
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
|
function asyncAdd(a,b,callback) { setTimeout(function(){ callback(null, a+b) },1000) }
async function sum(...rest) { }
let start = window.performance.now() sum(1, 2, 3, 4, 5, 6).then(res => { console.log(res) console.log(`程序执行共耗时: ${window.performance.now() - start}`) })
|
本题根据程序输出时间不同,可以划分为三个难度等级
- 青铜难度, 输出时长大于6秒
- 白银难度, 输出时长大于3秒
- 王者难度, 输出时长大于1秒
答案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| async function sum(...rest) { let result = rest.shift() for(let num of rest) { result = await new Promise(resolve => { asyncAdd(result, num, (_,res) => { resolve(res) }) }) } return result }
sum1(1, 2, 3, 4, 5,6).then(res => { console.log(`计算结果为:${res}`) })
|
在青铜难度,我们把数组里面的每一项依次相加。但是也可以进行一些优化,可以并发执行多个,比如 sum(1,2,3,4,5,6),可以同时执行 1+2,3+4,5+6,这样就可以提升执行效率
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 29 30 31 32
| async function sum(...rest) { if (rest.length <= 1) { return rest[0] || 0 } const promises = [] for (let i = 0; i < rest.length; i += 2) { promises.push( new Promise(resolve => { if (rest[i + 1] === undefined) { resolve(rest[i]) } else { asyncAdd(rest[i], rest[i + 1], (_, result) => { resolve(result) }) } }) ) } const result = await Promise.all(promises) return await sum(...result) }
sum1(1, 2, 3, 4, 5,6).then(res => { console.log(`计算结果为:${res}`) })
|
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
| async function sum(...rest) { let result = 0 const obj = {} obj.toString = function() { return result } const promises = [] for(let num of rest) { promises.push(new Promise((resolve) => { asyncAdd(obj, num, (_, res) => { resolve(res) }) }).then(res => { result = res })) } await Promise.all(promises) return result }
sum1(1, 2, 3, 4, 5,6).then(res => { console.log(`计算结果为:${res}`) })
|
因为js是执行在单线程里面的,所以上面的代码,我们在for of将所有的计算放到promises数组里面,然后通过Promise.all去一次性执行,这时候并不需要考虑到底先执行哪两个数字相加。因为单线程的原因,我们可以保证这几个Promise是依次执行的,这时候obj.toString返回值就是上一个Promise的返回值,多跑几遍代码你就懂了。