[英]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.