async/await实现Promise.all()

Posted 不叫猫先生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了async/await实现Promise.all()相关的知识,希望对你有一定的参考价值。

🐱个人主页:不叫猫先生
🙋‍♂️作者简介:专注于前端领域各种技术,热衷分享,期待你的关注。
💫系列专栏:vue3从入门到精通
📝个人签名:不破不立

目录

一、Promise.all()简介

Promise.all() 方法接收一个 promise 的 iterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且只返回一个Promise实例,并且输入的所有 promise 的 resolve 回调的结果是一个数组

  • Promise的 resolve 回调执行是在所有输入的 promise 的 resolve 回调都结束,或者输入的 iterable 里没有 promise 了的时候
  • Promise的 reject 回调执行是只要任何一个输入的 promise 的 reject 回调执行或者输入不合法的 promise 就会立即抛出错误,并且只要有 reject 就会立即抛出的错误信息

二、async/await实现Promise.all()

先定义三个Promise实例对象,并放置于一个数组中

        let a = new Promise((res, rej) => 
			res(1)
		).catch(err => console.log(err))
		let b = new Promise((res, rej) => 
			setTimeout(() => 
				rej(2)
			, 2000)
		).catch(err => console.log(err))
		let c = new Promise((res, rej) => 
			res(3)
		).catch(err => console.log(err))
       const arr = [a, b, c]

1、方式一

-使用async/await,循环遍历Promise实例对象的数组,并把每个Promise对象的结果放置于一个空数组中。

		async function bb() 
			let arr1 = [];
			try 
				for (let i = 0; i < arr.length; i++) 
					let h = await arr[i]
					arr1.push(h)
				
			 catch (err) 
			
			return arr1
		
		
		bb().then(res => 
			console.log(res); //[1, undefined, 3]
		);

undefined是因为await只处理成功时resolve(),不处理失败异常,故返回undefined

2、方式二

该方面类似实现手写Promise.acll(),等await拿到Promise结果然后count加1,知道count的数值等于数值的长度在resolve()

      const all = (arr) => 
  			return new Promise((resolve, reject) => 
				let length = arr && arr.length
				let count = 0
				let result = []
				if (!arr || arr.length === 0) 
					resolve(result)
				
				arr.forEach(async (item, index) => 
					try 
						const res = await item
						result[index] = res
						count++
						if (count === length ) 
							resolve(result)
						
					 catch (err) 
						reject(err)
					
				);
			)
		

三、async/await与Promise.all()结合使用

因为Promise.all()返回的也是Promise,所以await 后面可以跟Promise.all()

         function fn() 
			return new Promise((resolve, reject) => 
				resolve(Math.random())
			)
		
		async function asyncFunc() 
			let result
			try 
				result = await Promise.all([fn(), fn()])
				console.log(result)
			 catch (err) 
				console.log(err, 'err')
			
			return result
		
      asyncFunc().then(res =>  console.log(res, 'res') )

将 Async/Await 与 Promise.all 与 for 循环一起使用

【中文标题】将 Async/Await 与 Promise.all 与 for 循环一起使用【英文标题】:Using Async/Await vs Promise.all with for-loops 【发布时间】:2020-09-24 23:08:32 【问题描述】:

这是我目前的理解:

for 循环中的 async/await 应该暂停执行,直到 promise 解决,这意味着循环的下一次迭代在该行完成之前不会发生。

考虑以下数组:

const data = [];
for (let i = 0; i <= 100000; i++) 
    data.push(i);

方法一:在for循环中等待Promise

async function method1() 
  const startTime = new Date();
  console.log('start:', startTime);

  for (const item in data) 
    await new Promise(resolve => 
      if (item % 3 === 0) 
        resolve();
       else 
        resolve(item)
      
    );
  

  const endTime = new Date();
  console.log('finish:', endTime);
  console.log('total time:', endTime-startTime);

因为它需要顺序执行 Promise 才能继续循环,所以我认为使用 Promise.all 将是一种性能增强,可以在更大程度上利用异步处理:

方法 2:Promise.all 跟随 for 循环

async function method2() 
  const promises = [];
  const startTime = new Date();
  console.log('start:', startTime);

  for (const item in data) 
    const promise = new Promise(resolve => 
      if (item % 3 === 0) 
        resolve();
       else 
        resolve(item)
      
    );

    promises.push(promise);
  

  await Promise.all(promises);
  const endTime = new Date();
  console.log('finish:', endTime);
  console.log('total time:', endTime-startTime);

我的推理:当每个先前创建的 Promise 尝试解决时,循环将继续发出新的 Promise。所以在我看来,方法 1 = 阻塞......而方法 2 = 更少阻塞。

当我在 repl.it 上运行它们时,我发现方法 1 实际上更快,几乎快了 2 倍。有人可以解释为什么会这样吗?不应该反过来吗?

【问题讨论】:

这两种方法在概念上的区别在于,一种并行运行异步操作,另一种串行运行它们。使用虚假的异步操作,您看不到这种差异的真正效果。使用真正的异步操作,效果会很明显,并且并行运行会有更快的端到端时间。如果每个异步操作都需要 200ms 来解析,那么方法 1 将在 ~n * 200ms 中解析,而方法 2 将在 ~200ms 中解析,其中 n 是您运行的异步操作的数量。 【参考方案1】:

我的猜测是你解析太快了,所以循环支配了执行时间,因为method2有两个循环:一个推入数组,一个promise.all完成,而method1只有一个循环,所以你的感觉“几乎是两倍”实际上在理论上是正确的。

尝试像new Promise(resolve =&gt; setTimeout(resolve, 200)) 那样伪装actual async operation,你应该会得到你所期望的

【讨论】:

工作就像一个魅力。我想尝试用同步操作来测试异步进程并没有什么意义吧 @stoneb 虽然您的代码解析了一个非异步值,但您的代码也是异步的,只是“异步”部分发生得太快了【参考方案2】:

进一步补充 Drake 所说的话。方法 2 在没有超时的情况下速度较慢的唯一原因是它必须遇到的循环数,但在请求或异步操作有延迟的实际场景中。方法 2 在大多数情况下会更快

这是修改后的带有 SetTimeout 的 sn-p。

const data = [];
for (let i = 0; i <= 1000; i++) 
    data.push(i);



async function method1() 
  const startTime = new Date();
  console.log('start 1:', startTime);

  for (const item in data) 
   await new Promise(resolve => 
      setTimeout(()=>
        if (item % 3 === 0) 
        resolve();
       else 
        resolve(item)
      
      ,1)
    );
  
  const endTime = new Date();
  console.log('finish 1:', endTime);
  console.log('total time:', endTime-startTime);


async function method2() 
  const promises = [];
  const startTime = new Date();
  console.log('start 2:', startTime);

  for (const item in data) 
    const promise = new Promise(resolve => 
      setTimeout(()=>
        if (item % 3 === 0) 
        resolve();
       else 
        resolve(item)
      
      ,1)
    );

    promises.push(promise);
  

  await Promise.all(promises);
  const endTime = new Date();
  console.log('finish 2:', endTime);
  console.log('total time:', endTime-startTime);


method1()
method2()

【讨论】:

感谢您的代码块。这澄清了很多事情!

以上是关于async/await实现Promise.all()的主要内容,如果未能解决你的问题,请参考以下文章

promise,async await,try catch的问题整理

promise/axios async/await使用方法汇总

Promise原理讲解 async+await应用(异步回调解决方案)

JS Async / Await与forEach不兼容

处理 Array#map 中的 async/await 中的错误(拒绝)

无法访问 for 循环中使用的链式 Promise 内的外部范围变量