【问题标题】:Doing an async operation on each item while doing a "double iteration" on an array在对数组执行“双重迭代”的同时对每个项目执行异步操作
【发布时间】:2019-10-29 12:29:17
【问题描述】:

不知道术语是否正确,但我有一个对象数组,其中也有其他数组。我需要通过这些项目中的每一个。如果操作不是异步的,它看起来像这样:

myArray.forEach(x => {
  x.otherArray.forEach(y => {
    doSomething(y)
  })
})

然而doSomething 函数是async,不幸的是我很清楚在这些迭代期间我不能简单地通过几个异步和等待使其工作。

通常,当我需要在迭代期间执行承诺时,我会执行以下操作:

await myArray.reduce((p, item) => {
  return p.then(() => {
    return doAsyncSomething(item)
  })
}, Promise.resolve())

但是因为我同时进行两次迭代,这变得有点复杂,那我该怎么做呢?

我目前有这样的东西,但它似乎不是正确的方法:

await myArray.reduce((p, item) => {
    return item.someArray.reduce((promise, it, index) => {
      return promise.then(() => {
        return doAsyncSomething()
      })
    }, Promise.resolve())
  }, Promise.resolve())

我知道我可以通过两个forEach 将我的对象组织成一个数组,然后在其中执行reducedoSomething,但我怀疑这是完成它的最有效或最优雅的方式。那我该怎么做呢?

【问题讨论】:

    标签: javascript arrays async-await


    【解决方案1】:

    试试这个:

    let objArray = [ {otherArray: [1,2]}, {otherArray: [3,4]}, {otherArray: [5,6]} ];
    
    function doAsyncSomething(item) {
        return Promise.resolve(item);
    }
    
    async function doit() {
        let s = 0;
        for(const x of objArray)
            for(const y of x.otherArray)
                s+= await doAsyncSomething(y);
    
        return s;
    }
    
    doit().then(v => {
      console.log(v);
    });
    

    或尝试这样的递归调用:

    let objArray = [ {otherArray: [1,2]}, {otherArray: [3,4]}, {otherArray: [5,6]} ];
    let index = 0;
    let subIndex = 0;
    
    function doAsyncSomething(item) {
        return new Promise(resolve => {
            console.log("proc item", item);
            resolve(item);
        });
    }
    
    async function doit() {
        return await doAsyncSomething(objArray[index].otherArray[subIndex]);
    }
    
    function go() {
        doit().then(v => {
            console.log(v);
    
            subIndex++;
            if (subIndex >= objArray[index].otherArray.length) {
                subIndex = 0;
                index++;
            }
            if (index < objArray.length)
                go();
        });
    }
    

    【讨论】:

      【解决方案2】:

      reduce 时将 promise 传递到内部循环:

        await myArray.reduce((p, item) =>
          item.someArray.reduce((p, it, index) => 
            p.then(() => doAsyncSomething(it)),
            p // <<<
          ), 
          Promise.resolve()
        )
      

      或者我更喜欢:

        for(const { someArray } of myArray) {
          for(const it of someArray) {
             await doSomethingAsync(it);
          }
       }
      

      如果你想并行运行任务:

        await Promise.all(
          myArray.flatMap(item => item.someArray.map(doSomethingAsnyc))
       );
      

      【讨论】:

        【解决方案3】:

        假设您希望所有操作并行发生,您可以使用Promise.all()

        async function () { // I assume you already have this
        
          // ...
        
          let asyncOps = [];
        
          myArray.forEach(x => {
            x.otherArray.forEach(y => {
              asyncOps.push(doSomething(y));
            })
          })
        
          await Promise.all(asyncOps);
        }
        

        function doSomething (x) {
            return new Promise((ok,fail) => 
                setTimeout(() => {
                    console.log(x);
                    ok();
                },10));
        }
        
        let foo = [[1,2,3,4],[5,6,7,8]];
        
        async function test() {
            let asyncOps = [];
            foo.forEach(x => 
                x.forEach(y => 
                    asyncOps.push(doSomething(y))));
            
            await Promise.all(asyncOps);
        }
        
        test();

        如果你想按顺序执行异步操作,那就更简单了:

        async function () { // I assume you already have this
        
          // ...
        
          for (let i=0; i<myArray.length; i++) {
            let x = myArray[i];
            for (let j=0; j<x.length; j++) {
              let y = x[j];
        
              await doSomething(y);
        
            }
          }
        }
        

        【讨论】:

        • 不行,await 只能出现在 async 函数中。
        • 是的。假设 sn-p 在 async 函数内部。查看原帖
        • 感谢您的复仇投票 :) 您仍然应该尝试该代码...(您意识到 y =&gt; { 是一个常规的非异步函数?)
        • @JonasWilms 我没有投票。如您所见,我的代码有效。查看 sn-p
        • 你知道我没有推送y。我推送了doSomething() 的结果,这是一个异步函数
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-27
        • 2014-03-11
        • 2014-02-15
        • 1970-01-01
        • 2019-06-16
        • 2011-03-20
        相关资源
        最近更新 更多