在数组上执行“双重迭代”的同时对每个项目执行异步操作

时间:2019-06-14 21:39:40

标签: javascript arrays async-await

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

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将对象组织成一个数组,然后将reduce与其中的doSomething一起使用,但是我怀疑这是最有效或最优雅的方法完成的方式。那我该怎么办呢?

3 个答案:

答案 0 :(得分:2)

尝试一下:

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();
    });
}

答案 1 :(得分:0)

减少时将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))
 );

答案 2 :(得分:0)

假设您希望所有操作并行进行,则可以使用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);

    }
  }
}