簡體   English   中英

如何按順序執行承諾,從數組傳遞參數?

[英]How to execute promises sequentially, passing the parameters from an array?

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]))

現在,如果我執行上面的語句,它將按順序運行。 在我的實際用例中,數組是動態填充的,我需要為myArray中的每個成員執行myPromise() function 。

如何創建一個“可暫停循環”,它將為數組中的每個項目循環,執行myPromise並等待 promise 得到解決,然后再繼續下一次迭代?

如果您可以像問題中的情況一樣創建與數組元素一樣多的承諾,您可以將.then的重復應用非常整齊地折疊起來:

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)

它作為mapSeries內置於優秀的承諾庫 Bluebird 中:

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() )

不要創建一系列承諾。 創建一個返回承諾的函數數組。

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

承諾在創建后立即開始運行。 因此,只有在完成當前的承諾后,才能通過構建下一個承諾來確保順序執行。

您也可以通過遞歸方法來實現 - 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'); });

順序:

您可以使用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 ;
}

平行線:

對於並行,您可以只在循環中調用每個異步函數一次,但如果您確實想獲得它們的組合結果,則可以使用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 ;
    })
}


注意:我將各個參數視為列表列表,因為應將多個參數傳遞給任何一個函數,否則如果您只需要向每個參數傳遞一個參數,則可以刪除擴展運算符。

我知道我很晚了,我的回答與其他人發布的相似。 但我想我可以發布一個更清晰的答案,這可能對任何初學者都有幫助。

我們可以使用promise factory代替直接使用promise。 由於承諾在使用承諾工廠創建后立即開始執行,因此我們延遲了承諾的創建。

在這個例子中,我創建了 5 秒后解析。 我使用 promiseCreator 來創建承諾。 現在數組promises使用promiseCreator創建 5 個 promises 實例。 但陣列promiseFactories包裹promiseCreator的功能,所以承諾不會立即調用。 它在使用時被調用。

函數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)

你可以使用Array.reduce

//type: [number]
var myArray = [1, 2, 3, 4, 5, 6] //doesn't really matter

//type: number -> Promise<number>
function myPromise(num){
  return new Promise((resolve) => {
    window.setTimeout(()=>{
      resolve(console.log("done: " + num)  )
    },2000)
  })
}

//Array.reduce has type: [a] ~> ((b, a) -> b), b) -> b
//So it can have type:
//[number] ~> ((Promise<number>, number) -> Promise<number>), Promise<number>) -> Promise<number>
//Therefore we need to give reduce a function that takes a Promise 
//resolving to a number and a number which makes a new promise.
//This is the function we want:

function sequencePromises(promise, number) {
  return new Promise((resolve) => {
    resolve(promise.then(_ => myPromise(number)));
  });
} 

myArray.reduce(sequencePromises, Promise.resolve());

當然,如果您有一個可能出錯的 promise,或者如果您需要以前的結果,這種簡單的方法將不起作用,因此您可能希望使sequencePromises更通用:

function genericSequencePromises(promiseFunction) {
  return (promise, parameter) => {
    return new Promise((resolve, reject) => 
                         return promiseFunction(resolve, 
                                                reject, 
                                                promise, 
                                                parameter));
  }
}

然后你可以做任何你想做的事,只要你返回一個 Promise。

最后,您可能會從這個小幫手中受益:

function promiseSeries(array, reducer) {
  return array.reduce(reducer, Promise.resolve());
}

把它放在一起:

let sequencePromises = genericSequencePromises((resolve, reject, promise, num) => {
  resolve(promise.then(_ => console.log(`done: ${num}`)));
}

promiseSeries(myArray, sequencePromises);

這樣,您不僅可以處理問題中的案例,還可以處理更復雜的案例。

我會使用babel並這樣做:

 let args = [1, 2, 3]; const myPromise = async x => console.log('arg:',x); const test = async () => { for (let task of args.map(myPromise)) await task; } test().then(console.log('Done'));
 <script src="https://unpkg.com/babel-standalone@6.24.0/babel.min.js"></script>

您可以遍歷元素數組並像這樣傳遞參數:

 const arr = [1, 2, 3, 4, 5, 6]; const MyPromiseFunction = num => new Promise((resolve, reject) => { // Your logic... setTimeout(() => num <= 4 ? resolve('Success!') : reject('Rejected!'), 1000 * num); }); const logMessage = (num, msg) => console.log(`For number ${num} promise result: ${msg}`); arr.forEach( num => MyPromiseFunction(num) .then(message => logMessage(num, message)) .catch(reason => logMessage(num, reason)) );

 const myArray = [1, 2, 1000, 4, 5000, 6] const sleep = ms => new Promise(res => { setTimeout(res, ms) }) const myPromise = num => sleep(num).then(() => { console.log('done: ' + num) }) myArray.reduce( (p, x) => p.then(_ => myPromise(x)), Promise.resolve() )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM