Как избежать использования двух циклов при динамическом использовании Promise.all ()? - PullRequest
0 голосов
/ 03 декабря 2018

Всякий раз, когда вы видите, что Promise.all () используется, он обычно используется с двумя циклами, как я могу превратить его в один без использования async и , поддерживающих порядок выполнения ?

Вопрос не о порядке, я знаю, что promise.all сохраняет порядок, вопрос о том, как избежать двух циклов, когда вам просто нужно возвращаемое значение

function timeout(x){
 return new Promise( resolve => {
  setTimeout( () => {
    return resolve(x);
  },x)
 })
}

const promises = [];
const results = [];
//First loop, array creation
for (i = 0; i < 20; i++) { 
  const promise = timeout(i*100)
  promises.push(promise);
}

Promise.all(promises).then( resolvedP => {
    //Second loop, async result handling
    resolvedP.forEach( (timeout,i) => {
    results.push({
      index : i,
      timeout : timeout
    })
  })
  console.log(results);
})
//End of code

Теперь этоможно решить с помощью async, но в моем контексте я не могу использовать его, например:

//Only one loop
for (i = 0; i < 20; i++) {
  const timeoutAwait = await timeout(i*100);
  results.push({
      index : i,
      timeout : timeoutAwait
    })
}
console.log(results)
//End of code

Я попробовал следующее, но обещание не возвращает значение resolveбез использования .then():

for (i = 0; i < 20; i++) { 
  const promise = timeout(i*100)
  promises.push(promise);
  results.push({index : i, timeout : promise});
}

Promise.all(promises).then( resolvedP => {
    resolvedP.forEach( (timeout,i) => {
      results.push({
        index : i,
        timeout : timeout
      })
    })
    console.log(results);
    //results[0].timeout is a Promise object instead of 0
})
//End of code

Итак, есть ли способ сделать мой первый пример кода только в одном цикле?Пожалуйста, игнорируйте контекст, это только пример.

Ответы [ 3 ]

0 голосов
/ 03 декабря 2018

Мне будет проще понять, если вы отобразите массив значений вместо циклов:

const timeout = x=>Promise.resolve(x);

Promise.all(
  [...new Array(3).keys()]//array [0,1,2]
    .map(x=>timeout(x*100))//[timeout(0*100),timeout(1*100),...
).then(
  result=>result.map(//results of the timeout, map to object
    (timeout,index)=>({
      index,
      timeout
    })
  )
).then(
  result=>console.log('result:',result)
)

Обычно не рекомендуется асинхронно изменять общую переменную (массив результатов).Просто разрешите обещание и создайте нужный вам результат за последний .then, теперь ваше обещание преобразуется в значение, которое вы хотите.

0 голосов
/ 03 декабря 2018

Как и в документации Promise.all , порядок будет сохранен.В нем говорится о возвращаемом значении:

Ожидающее обещание во всех других случаях.Это возвращенное обещание затем разрешается / отклоняется асинхронно (как только стек пуст), когда все обещания в данной итерируемой разрешены или если одно из обещаний отклонено.См. Пример об «Асинхронности или синхронности Promise.all» ниже. Возвращаемые значения будут в порядке пройденных Обещаний, независимо от порядка выполнения.

(выделено мной).

0 голосов
/ 03 декабря 2018

function timeout(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      return resolve(x);
    }, x);
  });
}

const promises = [];
const results = [];
//First loop, array creation
for (let i = 0; i < 20; i++) {
  const promise = timeout(i * 100).then(x => results.push({
    index: i,
    timeout: x
  }));
  promises.push(promise);
}
Promise.all(promises).then(() => {
  console.log(results);
});

Если вы хотите сохранить результаты выполнения / назначения результатов, используя индекс i вместо .push

const promise = timeout(i * 100).then(x => results[i] = {
  index: i,
  timeout: x
});
...