js 异步循环

文章介绍了在JavaScript中如何在循环中处理Promise异步操作,包括如何在所有异步操作结束后执行某操作,以及如何按顺序等待每个异步操作完成。提到了使用for循环、forEach、Promise.all()以及async/await的方法,并通过分片上传的场景解释了顺序执行的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

在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都是不生效的;

JavaScript中,可以使用async/await和Promise来实现异步循环直到状态更改。 使用async/await的方式可以让代码看起来更加简洁和易懂。下面是一个异步循环的示例代码: ```javascript async function waitUntilStatusChanges() { while (true) { const status = await getStatus(); if (status === 'changed') { console.log('Status changed!'); break; } console.log('Status not yet changed'); await sleep(1000); // 等待1秒钟 } } async function getStatus() { // 异步获取状态的代码 } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } ``` 在上面的代码中,我们使用`async/await`来等待异步函数`getStatus()`的返回结果。如果状态没有改变,我们会等待1秒钟,并再次调用`getStatus()`。如果状态已经改变,我们会打印`Status changed!`并跳出循环。 另外,我们还编写了一个`sleep()`函数来等待1秒钟。这个函数返回一个Promise,等待指定的时间后再resolve。 如果您不想使用`async/await`,可以使用Promise来实现异步循环。下面是一个使用Promise的示例代码: ```javascript function waitUntilStatusChanges() { return new Promise((resolve, reject) => { const checkStatus = () => { getStatus() .then(status => { if (status === 'changed') { console.log('Status changed!'); resolve(); } else { console.log('Status not yet changed'); setTimeout(checkStatus, 1000); // 等待1秒钟 } }) .catch(error => reject(error)); }; checkStatus(); }); } function getStatus() { // 异步获取状态的代码 } ``` 在上面的代码中,我们使用一个递归函数`checkStatus()`来等待异步函数`getStatus()`的返回结果。如果状态没有改变,我们会等待1秒钟,并再次调用`checkStatus()`。如果状态已经改变,我们会resolve Promise。 总的来说,无论是使用async/await还是Promise,JavaScript都可以实现异步循环直到状态更改的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值