如何顺序执行promises,从数组传递参数?

Dav*_*lsh 20 javascript

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]))
Run Code Online (Sandbox Code Playgroud)

现在,如果我执行上面的语句,它将按顺序运行.在我的实际用例中,数组是动态填充的,我需要myPromise()为每个成员执行该函数myArray.

我如何创建一个"可暂停的循环",它将为数组中的每个项循环,执行myPromise并等待承诺得到解决,然后再继续下一次迭代?

Ry-*_*Ry- 42

.then如果您可以像创建问题中的情况那样创建与数组元素一样多的promise,那么您可以将重复应用程序整齐地复制到折叠中:

myArray.reduce(
  (p, x) =>
    p.then(_ => myPromise(x)),
  Promise.resolve()
)
Run Code Online (Sandbox Code Playgroud)

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

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

mapSeries(myArray, myPromise)
Run Code Online (Sandbox Code Playgroud)

这是优秀的诺言图书馆Bluebird内置的mapSeries:

Promise.mapSeries(myArray, myPromise)
Run Code Online (Sandbox Code Playgroud)

Runnable片段:

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()
)
Run Code Online (Sandbox Code Playgroud)

  • 如果你需要返回所有结果,如`Promise.all` - `myArray.reduce((p,x)=> p.then(results => fn(x).then(r => results.concat(r) )),Promise.resolve([])).then(results => {});` (7认同)
  • @JaromandaX:`concat` 的副本数量是 1,然后是 2,然后是 3,……。经验法则:永远不要用“concat”或“spread”来“reduce”。 (3认同)

Mas*_*ief 12

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

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

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

函数按顺序executeSequentially执行所有操作promiseLike

  • promise传递数组时,结果是promise数组本身并行执行(实际上它们在创建后立即执行,而不是在调用此行时执行)。
  • promiseFactory数组传递时,结果是新的 Promise,当先前的 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)
Run Code Online (Sandbox Code Playgroud)


jdh*_*dh8 8

不要创建一个承诺数组.创建一个返回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()
})()
Run Code Online (Sandbox Code Playgroud)

Promise在创建后立即开始运行.因此,通过仅在完成当前承诺之后构造下一个承诺来确保顺序执行.

  • 在 for 循环子句本身内转换数组以进行迭代的巧妙技巧。我喜欢这种代码,但如果我与其他人一起工作,我会将其分成两个语句以提高可读性 (2认同)

Moh*_*uri 6

顺序:

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

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

Run Code Online (Sandbox Code Playgroud)

平行线:

对于并行,您可以在循环中调用每个异步函数一次,但如果您确实想获得它们的组合结果,您可以使用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 ;
    })
}


Run Code Online (Sandbox Code Playgroud)

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


Sla*_*nov 5

您也可以通过递归方法来实现 -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');
});
Run Code Online (Sandbox Code Playgroud)