js 异步循环


前言

在js中某些场景需要用到数组循坏中使用异步的操作,在这种情况下我们可能会面临这些问题

如:

  1. 如何让所有的循环中的Promise异步操作结束后执行再执行某个操作
  1. 如何在循环中的Promise异步操作按顺序等待上一个完成后再执行下一个异步操作

这是我的一些实现思路,如下


如何让所有的循环中的Promise异步操作结束后执行某个操作

定义一个异步方法

  function myFunc(num, s = 1000) {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve("我是数组的第"+ num + '项');
      }, s);
    });
  }

标记计数法

定义一个初始为0的变量,每次循环异步结束后+1,直到变量和数组长度相同,就可以判断为当前异步操作全部完成

代码如下:

使用for(推荐)

      let flag = 0 // 标记变量
      let arr = [6, 2, 3, 4, 5] // 循环数据

      // 使用for
      for (let i = 0; i < arr.length; i++) {
        myFunc(i, arr[i]).then(res => { // myFunc异步方法
          flag++ // 每次返回结果后+1
          console.log(res)

          if (flag === arr.length) {
            console.log('这里的块级作用域为所有异步循环完成后')
          }
        })
      }

使用forEach

      let flag = 0 // 标记变量
      let arr = [1, 2, 3, 4, 5] // 循环数据

      arr.forEach((item, idx) => {
        myFunc(idx, item).then(res => { // myFunc异步方法
          flag++ // 每次返回结果后+1
          console.log('单个异步回调')

          if (flag === arr.length) {
            console.log('这里的块级作用域为所有异步循环完成后')
          }
        })
      })

使用es9方法 for await of

      let flag = 0 // 标记变量
      let arr = [1, 2, 3, 4, 5] // 循环数据

      const promise_all = arr.map(item => myFunc(item))

      async function test() {
        for await (const prop of promise_all) {
          flag++ // 每次返回结果后+1
          console.log('单个异步回调')

          if (flag === arr.length) {
            console.log('这里的块级作用域为所有异步循环完成后')
          }
        }
      }
      test()

Promise.all()

可以使用Promise.all()将Promise实例,包装成一个新的 Promise 总实例

首先利用循环生成实例
在执行合并起来的promise异步实例

  const Promise_All = Promise.all(arr.map(item => Files.findOne(item))) // Files.findOne异步方法

  const res = await Promise_All // 执行总实例
  console.log(res, '所有异步循环完成后')

如何在循环中的异步操作按顺序等待上一个完成后再执行下一个异步操作

这种需求通常用于第二个异步方法需要获取上一个异步方法返回的状态才能进行下一步,或者在使用分片上传时,将分片文件按顺序上传

假设模拟分片上传场景

let flag = 0 // 标记变量
let arr = [3, 2, 1, 3, 2] // 循环数据 

// 使用for
for (let i = 0; i < arr.length; i++) {
  myFunc(i, arr[i]).then(res => { // myFunc异步方法
    flag++ // 每次返回结果后+1
    console.log(`${i}个分片文件上传完了`)
    if (flag === arr.length) {
      console.log('所有分片文件都上传完了')
    }
  })
}

在这里插入图片描述

可以看到由于是异步,谁先最快就返回谁,这肯定不符合我们的需求,导致产生莫名奇妙的bug

怎么实现执行等待呢,其实很简单,在上面异步循环原有例子中 增加 await即可

let flag = 0 // 标记变量
let arr = [3, 2, 1, 3, 2] // 循环数据 

// 使用for
async function test() {
  for (let i = 0; i < arr.length; i++) {
    await myFunc(i, arr[i]).then(res => { // myFunc异步方法
      flag++ // 每次返回结果后+1
      console.log(`${i}个分片文件上传完了`)
      if (flag === arr.length) {
        console.log('所有分片文件都上传完了')
      }
    })
  }
}
test()

在这里插入图片描述

这样就可以按顺序执行了,解决

注意:

实际开发中for、while、for in、for of、for await of使用await都是生效的;其中for await of是等待整个for循环作用域,异步返回后才执行当前作用域下的其他操作;而其他则是局部等待

有回调的遍历方法:forEach、map、filter、reduce、some、every、find等,使用await都是不生效的;

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript中,当我们在循环中调用异步方法时,可能会遇到一些问题。引用[1]中提到了一个例子,使用map方法在循环中调用异步方法并打印索引值。在这个例子中,由于异步方法的执行时间比循环快,导致输出结果都是5,而不是预期的0、1、2、3、4。这是因为每次循环结束后,setTimeout的回调函数中的i指向的是循环结束时的最终值,而不是当前循环的索引值。 为了解决这个问题,可以使用async/await关键字来处理异步方法。引用中给出了一个示例代码,使用了async/await关键字来在map方法中调用异步方法。在这个例子中,通过在异步函数前面加上async关键字,并使用await关键字来等待异步方法的返回结果,确保了异步方法执行完毕后再进行下一次循环。这样就能够正确地打印每次循环的索引值。 另外,如果需要在循环中处理多个异步方法的返回结果,也可以使用Promise.all方法来等待所有异步方法的返回结果。这样可以保证所有异步方法都执行完毕后再进行下一步操作。 所以,在JavaScript循环中调用异步方法时,可以使用async/await关键字来确保异步方法的顺序执行,或者使用Promise.all来等待所有异步方法执行完毕。这样可以避免出现异步方法执行顺序不正确的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值