Выполнение асинхронной операции над каждым элементом при выполнении «двойной итерации» над массивом - PullRequest
2 голосов
/ 15 июня 2019

Не знаю, правильна ли терминология, но у меня есть массив объектов, в котором также есть другие массивы. Мне нужно пройти через каждый из этих пунктов. Если операция не была асинхронной, она выглядела бы примерно так:

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 ]

2 голосов
/ 15 июня 2019

попробуйте это:

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();
    });
}
0 голосов
/ 15 июня 2019

Если вы хотите, чтобы все операции выполнялись параллельно, вы можете использовать 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);

    }
  }
}
0 голосов
/ 15 июня 2019

Передайте обещание во внутренний цикл при уменьшении:

  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))
 );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...