一道字节笔试题,实现一个异步求和函数

数据库 MySQL
我们可以两两一组,使用 Promise.all 求和,再把和两两一组继续求和…..,知道只剩余一个就是最终的结果.

[[396984]]

题目:

提供一个异步 add 方法如下,需要实现一个 await sum(...args) 函数:

  1. function asyncAdd(a, b, callback) { 
  2.   setTimeout(function () { 
  3.     callback(null, a + b); 
  4.   }, 1000); 

简化:两数之和

我们先来简单的实现一个异步两数之和函数

  1. function sumT(a, b) { 
  2.     return await new Promise((resolve, reject) => { 
  3.         asyncAdd(a, b, (err, res) => { 
  4.             if(!err) { 
  5.                 resolve(res) 
  6.             } 
  7.             reject(err) 
  8.         }) 
  9.     }) 
  10.  
  11. // 测试 
  12. const test = await sumT(1, 2) 
  13. console.log(test) 
  14. // 3 

加深:多数之和

上面我们实现了两数之和,然后扩展到多数之和喃?

提到数组求和问题,我们首先想到的是 reduce

reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。

—— MDN

  1. arr.reduce(callback(acc, cur[, idx[, arr]])[, initialValue]) 

callback 函数接收4个参数:

  • acc :累计器
  • cur :当前值
  • idx :当前索引
  • arr :源数组

其中, initialValue 可选,

  • 如果有 initialValue :acc 取值为 initialValue , cur 取数组中的第一个值
  • 如果没有:acc 取数组中的第一个值, cur 取数组中的第二个值
  1. const arr = [1, 2, 3, 4]; 
  2. const reducer = (acc, cur) => acc + cur; 
  3.  
  4. // 1 + 2 + 3 + 4 
  5. console.log(arr.reduce(reducer)); 
  6. // 输出: 10 
  7.  
  8. // 5 + 1 + 2 + 3 + 4 
  9. console.log(arr.reduce(reducer, 5)); 
  10. // 输出: 15 

关于本题:来自@champkeh

设置初始值为 Promise.resolve(0) ,经历 5 次求和:

  1. function sum(...args) { 
  2.     return new Promise(resolve => { 
  3.         args.reduce((acc, cur) => acc.then(total => sumT(total, cur)), Promise.resolve(0)).then(resolve) 
  4.     }) 
  5.  
  6. // 测试 
  7. await sum(1, 2, 3, 4, 5) 
  8. // 15 

但这存在一个耗时较长的问题,我们可以计算下时间:

  1. console.time("sum"
  2. // 测试 
  3. await sum(1, 2, 3, 4, 5) 
  4. // 15 
  5. console.timeEnd("sum"

也就是说,我们每次求和都会花费 1s,串行异步求和,这显然不是最优的

优化:使用 Promise.all

我们可以两两一组,使用 Promise.all 求和,再把和两两一组继续求和…..,知道只剩余一个就是最终的结果

  1. async function sum(...args) { 
  2.     // 用于考察每次迭代的过程 
  3.     console.log(args)  
  4.      
  5.     // 如果仅有一个,直接返回 
  6.     if(args.length === 1) return args[0] 
  7.     let result = [] 
  8.     // 两两一组,如果有剩余一个,直接进入 
  9.     for(let i = 0; i < args.length - 1; i+=2) { 
  10.         result.push(sumT(args[i], args[i + 1])) 
  11.     } 
  12.     if(args.length%2)  result.push(args[args.length-1]) 
  13.     // Promise.all 组内求和 
  14.     return sum(...await Promise.all(result)) 
  15.  
  16. // 测试 
  17. test = await sum(1, 2, 3, 4, 5) 
  18. // 15 

  1. console.time("sum"
  2. await sum(1, 2, 3, 4, 5) 
  3. console.timeEnd("sum"

 

来自:https://github.com/Advanced-Frontend/Daily-Interview-Question

 

责任编辑:武晓燕 来源: 三分钟学前端
相关推荐

2021-05-09 19:42:25

笔试题前端算法

2014-04-29 14:58:24

笔试题微软笔试题

2022-04-08 07:52:17

CSS面试题HTML

2021-05-31 07:55:44

smartRepeatJavaScript函数

2021-01-26 13:14:14

js前端map

2009-08-11 15:09:44

一道面试题C#算法

2011-06-14 09:12:03

JavaScript

2009-06-22 13:43:00

java算法

2012-07-03 09:38:42

前端

2011-05-23 11:27:32

面试题面试java

2019-09-02 15:06:16

面试字节跳动算法

2009-08-11 14:59:57

一道面试题C#算法

2018-03-06 15:30:47

Java面试题

2024-03-18 13:32:11

2009-08-11 10:12:07

C#算法

2023-08-01 08:10:46

内存缓存

2023-02-04 18:24:10

SeataJava业务

2017-11-21 12:15:27

数据库面试题SQL

2022-02-08 18:09:20

JS引擎解析器

2019-11-12 12:34:15

人工智能机器学习技术
点赞
收藏

51CTO技术栈公众号