动态使用Promise.all()时如何避免使用两个循环?

时间:2018-12-03 14:55:37

标签: javascript ecmascript-6 es6-promise

每当您看到Promise.all()被使用时,通常将其与两个循环一起使用,如何将其变成一个而没有使用异步维护执行顺序 >?

问题不是顺序,我知道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时,promise不会返回.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 :(得分:1)

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

答案 1 :(得分:1)

Promise.all documentation一样,订单将被保留。它说明了返回值:

  

在所有其他情况下的待定承诺。然后,这个返回的承诺   异步解决/拒绝(堆栈为空时)   给定迭代中的所有诺言都已解决,或者   承诺拒绝。请参阅有关“异步性或   Promise.all的同步性”。返回的值将按顺序排列   不论完成顺序如何,都可以通过。

(由我突出显示。)

答案 2 :(得分:0)

如果您映射到值的数组而不是循环,我会更容易理解

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中创建所需的结果,现在您的承诺就可以解决为您想要的值。