如何按顺序执行Promise,从数组中传递参数?

IT技术 javascript
2021-02-06 15:05:47
var myArray = [1, 2, 3, 4, 5, 6]

function myPromise(num){
  return new Promise(res => {
    window.setTimeout(()=>{
      res(  console.log("done: " + num)  )
    },2000)
  })
}


myPromise(myArray[0])
  .then(x => myPromise(myArray[1]))
  .then(x => myPromise(myArray[2]))
  .then(x => myPromise(myArray[3]))
  .then(x => myPromise(myArray[4]))
  .then(x => myPromise(myArray[5]))

现在,如果我执行上面的语句,它将按顺序运行。在我的实际使用情况阵列动态填充,我需要执行该myPromise()功能中的每个成员myArray

如何制作一个“可暂停循环”,循环数组中的每个项目,myPromise在继续下一次迭代之前执行并等待Promise得到解决?

6个回答

如果您可以.then像问题中的情况一样创建与数组元素一样多的Promise,那么您可以非常巧妙地将的重复应用到折叠中:

myArray.reduce(
  (p, x) =>
    p.then(_ => myPromise(x)),
  Promise.resolve()
)

但是,例如,异步函数不需要:

const mapSeries = async (iterable, action) => {
  for (const x of iterable) {
    await action(x)
  }
}

mapSeries(myArray, myPromise)

它内置于优秀的Promise库 Bluebird 中mapSeries

Promise.mapSeries(myArray, myPromise)

可运行片段:

const myArray = [1, 2, 3, 4, 5, 6]

const sleep = ms =>
  new Promise(res => {
    setTimeout(res, ms)
  })

const myPromise = num =>
  sleep(500).then(() => {
    console.log('done: ' + num)
  })

myArray.reduce(
  (p, x) =>
    p.then(_ => myPromise(x)),
  Promise.resolve()
)

如果您需要返回的所有结果Promise.all-myArray.reduce((p, x) => p.then(results => fn(x).then(r => results.concat(r))), Promise.resolve([])).then(results => {});
2021-03-16 15:05:47
并返回上面 mapSeries 示例的结果: const mapSeries = async (iterable, action) => { let res = [] for (const x of iterable) { res.push(await action(x)) } return res }
2021-03-26 15:05:47

不要创建一系列Promise。创建一个返回Promise的函数数组。

const f = x => new Promise(resolve => setTimeout(() => resolve(console.log(x)), 2000))

(async () => {
    for (let job of [1, 2, 3, 4, 5, 6].map(x => () => f(x)))
        await job()
})()

Promise在创建后立即开始运行。因此,只有在完成当前的Promise后,才能通过构建下一个Promise来确保顺序执行。

在 for 循环子句本身内转换数组以进行迭代的巧妙技巧。我喜欢这种代码,但如果我和其他人一起工作,我会将它分成两个语句以提高可读性
2021-03-23 15:05:47

顺序:

您可以使用async await功能按顺序运行Promise。这是一个片段

async function chainPromiseCalls(asyncFunctions=[],respectiveParams=[]){

    for(let i=0;i<asyncFunctions.length;i++){
        const eachResult = await asyncFunctions[i](...respectiveParams[i]);
        // do what you want to do with each result 
       
    }

    return ;
}

平行线:

对于并行,您只需在循环中调用每个异步函数一次,但如果您确实想获得它们的组合结果,则可以使用 Promise.all

function parallelPromiseCalls(asyncFunctions=[],respectiveParams=[]){
    return Promise.all(asyncFunctions.map((func,index)=>func(...respectiveParams[index])))
       .then(resultsList=>{
        resultsList.forEach((result,index)=>{
           // do what you want to do with each result in the list
        })
        return ;
    })
}


注意:我将各个参数视为列表列表,因为应将多个参数传递给任何一个函数,否则如果您只需要向每个参数传递一个参数,则可以删除扩展运算符。

您也可以通过递归方法来实现 -executeSequentially调用自身:

function createPromise(x) {
  return new Promise(res => {
    setTimeout(() => {
      console.log(x)
      res(x);
    }, x * 1000)
  })
}

function executeSequentially(array) {  
  return createPromise(array.shift())
    .then(x => array.length == 0 ? x : executeSequentially(array));
}

console.time('executeSequentially');
executeSequentially([1, 2, 3]).then(x => {
  console.log('last value: ' + x);
  console.timeEnd('executeSequentially');
});

如果数组在执行期间可以更改,则递归方法很有用。使用 Array.reduce 会立即生成所有执行器函数,而这里的递归方法会在最后一个 promise 被解析后生成每个执行器函数。
2021-03-20 15:05:47

我知道我很晚了,我的回答与其他人发布的相似。但我想我可以发布一个更清晰的答案,这可能对任何初学者都有帮助。

我们可以使用promise factory代替直接使用promise。由于Promise在使用Promise工厂创建后立即开始执行,因此我们延迟了Promise的创建。

在这个例子中,我创建了 5 秒后解析。我使用 promiseCreator 来创建Promise。现在该数组promises用于promiseCreator创建 5 个 Promise 实例。但是数组promiseFactories包装promiseCreator在一个函数中,因此不会立即调用 promise。它在使用时被调用。

函数executeSequentially全部promiseLike按顺序执行

  • promise传递数组时,结果是promise数组本身并行执行(实际上,它们在创建后立即执行,而不是在调用此行时执行)。
  • promiseFactory传递数组时,结果是新的 Promise 在先前的 Promise 完成执行时被创建。

const promiseCreator = (i, time, text) => {
    return new Promise(resolve => setTimeout(
        () => resolve(console.log(`${i} ${text}`)),
        time)
    );
}

const promises = [
    promiseCreator(1, 1000, "parallel"),
    promiseCreator(2, 1000, "parallel"),
    promiseCreator(3, 1000, "parallel"),
    promiseCreator(4, 1000, "parallel"),
    promiseCreator(5, 1000, "parallel"),
]

const promiseFactories = [
    () => promiseCreator(1, 1000, "sequential"),
    () => promiseCreator(2, 1000, "sequential"),
    () => promiseCreator(3, 1000, "sequential"),
    () => promiseCreator(4, 1000, "sequential"),
    () => promiseCreator(5, 1000, "sequential"),
]

function executeSequentially(promiseLikeArray) {
    var result = Promise.resolve();
    promiseLikeArray.forEach(function (promiseLike) {
        result = result.then(promiseLike);
    });
    return result;
}

executeSequentially(promises)
executeSequentially(promiseFactories)

这个例子不是已经做到了。传递给executeSequentially具有不同参数的 promises 或 promiseFactory(s) 你能澄清一下你在哪个部分感到困惑。乐于帮助。我也同意executeSequentially评分者对该功能的词选择不当。它更像是tryToExecuteSequentiallty因为它最终取决于是通过Promise还是通过Promise工厂。
2021-03-22 15:05:47
您能否阐明有关如何按顺序调用Promise的示例?说,我有一个名为“myPromise”的Promise,我想用不同的参数依次调用 5 次。
2021-03-25 15:05:47