最近老踩坑,在forEach里面,使用async和await不起效果,然后百度后发现原因,所以记录一下。先举个栗子:

  <script>
    let arr = [1, 2, 3];
    let newArr = [11, 22]

    function RunFn() {
      newArr.forEach(async it => {
        let text = await proRun();
        console.log(it);
        console.log(text);

        arr.forEach(async item => {
          let name = await proTest();
          console.log(item);
          console.log(name);
        });
      })
      console.log('end');
    };
    
    RunFn();

    function proRun() {
      return new Promise((resolve, reject) => {
        setTimeout(function () {
          resolve('我是第一个promise')
        }, 1500)
      })
    }

    function proTest() {
      return new Promise((resolve, reject) => {
        setTimeout(function () {
          resolve('我回来了')
        }, 1000)
      })
    }
  </script>

以上代码块,理想的执行顺序是:
11
‘我是第一个promise’
22
‘我是第一个promise’
1
‘我回来了’
2
‘我回来了’
3
‘我回来了’
1
‘我回来了’
2
‘我回来了’
3
‘我回来了’
‘end’

但是实际的数据顺序是:
在这里插入图片描述
会发现end,先被执行了,百度后,大概就是这样说的:

1、首先这是因为foreach是没有return返回值的(foreach内部实现只是简单的回调)

2、而foreach里面的回调函数因为加了async的原因,所以默认会返回一个promise,但是因为foreach的实现并没有返回值,所以导致返回的这个promise对象没人去管了

总的原因大概就是一句话:forEach 只支持同步,不支持异步

解决方法:

  1. for 循环:
    所以要保证end先执行,就要把forEach更换,我最开始采用的是for循环,代码如下:
    async function RunFn() {
      for(let i=0;i<newArr.length;i++){
        let text = await proRun();//''我是第一个promise''
        console.log(newArr[i]);
        console.log(text);

        for(let j=0;j<arr.length;j++){
          let name = await proTest();
          console.log(arr[j]);
          console.log(name);//''我回来了''
        }
      }
      console.log('end');
    };

    RunFn();

执行顺序如下:
在这里插入图片描述
可以看见,结果确实跟预期的一样,并且执行顺序是从上到下一次执行的;但是由于for循环,如果次数多了我是很抗拒的,于是乎还是采用有返回值的map进行:

2. map():
先来一个简单的栗子:

  <script>
    let arr = [1, 2, 3];

    async function RunFn() {
      let map1Promise = await arr.map(async it => {
        let text = await proRun(); //''我是第一个promise''
        console.log(it);
        console.log(text);
      });
      console.log(map1Promise); // return=>>[Promise, Promise]
      console.log('end');
    };

    RunFn();

    function proRun() {
      return new Promise((resolve, reject) => {
        setTimeout(function () {
          resolve('我是第一个promise')
        }, 1500)
      })
    }
  </script>

执行顺序:
在这里插入图片描述
这里可以看出map返回的是一个包含promise对象的数组[promise, promise, promise],然而await只能处理一个promise对象,所以就可以采用Promise.all()的方法:

  <script>
    let arr = [1, 2, 3];

    async function RunFn() {
      await Promise.all(arr.map(async it => {
        let text = await proRun(); //''我是第一个promise''
        console.log(it);
        console.log(text);
      }))
      console.log('end');
    };

    RunFn();

    function proRun() {
      return new Promise((resolve, reject) => {
        setTimeout(function () {
          resolve('我是第一个promise')
        }, 1500)
      })
    }
  </script>

执行顺序为:
在这里插入图片描述
最后在去试试之前的多个循环:

  <script>
    let arr = [1, 2, 3];
    let newArr = [11, 22]

    async function RunFn() {
      await Promise.all(newArr.map(async it => {
        let text = await proRun(); //''我是第一个promise''
        console.log(it);
        console.log(text);
        await Promise.all(arr.map(async item => {
          let name = await proTest();
          console.log(item);
          console.log(name); //''我回来了''
        }));
      }))
      console.log('end');
    };

    RunFn();

    function proRun() {
      return new Promise((resolve, reject) => {
        setTimeout(function () {
          resolve('我是第一个promise')
        }, 1500)
      })
    }

    function proTest() {
      return new Promise((resolve, reject) => {
        setTimeout(function () {
          resolve('我回来了')
        }, 1000)
      })
    }
  </script>

执行顺序:
在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐