Javascript 如何按顺序执行承诺,从数组中传递参数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43082934/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to execute promises sequentially, passing the parameters from an array?
提问by David Alsh
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]))
Right now, if I execute the statement above, it will run sequentially. In my actual use case the array is dynamically populated and I need to execute the myPromise()function for each member in myArray.
现在,如果我执行上面的语句,它将按顺序运行。在我的实际使用情况阵列动态填充,我需要执行该myPromise()功能中的每个成员myArray。
How can I make a "pauseable loop" that will loop for each item in the array, execute myPromiseand wait for the promise to be resolved before continuing to the next iteration?
如何制作一个“可暂停循环”,该循环将循环数组中的每个项目,myPromise在继续下一次迭代之前执行并等待承诺得到解决?
回答by Ry-
You can make the repeated application of .theninto a fold pretty neatly if you're okay with creating as many promises as array elements as is the case in the question:
如果您可以.then像问题中的情况一样创建与数组元素一样多的承诺,那么您可以非常巧妙地将的重复应用到折叠中:
myArray.reduce(
(p, x) =>
p.then(_ => myPromise(x)),
Promise.resolve()
)
but an async function, for example, doesn't require that:
但是,例如,异步函数不需要:
const mapSeries = async (iterable, action) => {
for (const x of iterable) {
await action(x)
}
}
mapSeries(myArray, myPromise)
which is built into the excellent promise library Bluebird as mapSeries:
它内置于优秀的承诺库 Bluebird 中mapSeries:
Promise.mapSeries(myArray, myPromise)
Runnable snippet:
可运行的片段:
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()
)
回答by jdh8
Don't create an array of promises. Create an array of functions returning a 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()
})()
Promises start running immediately after creation. Therefore, sequential execution is ensured by constructing the next promise only after finishing the current one.
承诺在创建后立即开始运行。因此,只有在完成当前的承诺后,才能通过构建下一个承诺来确保顺序执行。
回答by Slava Utesinov
Also you can do it via recursive approach - executeSequentiallycalls itself:
您也可以通过递归方法来实现 -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');
});
回答by MOHANTEJA
Sequential:
顺序:
you can use async awaitfeatures to run promises sequentially . here's a snippet
您可以使用async await功能按顺序运行承诺。这是一个片段
async function chainPromiseCalls(asyncFunctions=[],respectiveParams=[]){
for(let i=0;i<asyncFunctions.length;i++){
const eachResult = await asyncFunction[i](...respectiveParams[i]);
// do what you want to do with each result
}
return ;
}
Parallel:
平行线:
for parallel you can just call each async function once in a loop , but if you do want to get their combined result , you can use Promise.all
对于并行,您只需在循环中调用每个异步函数一次,但如果您确实想获得它们的组合结果,则可以使用 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 ;
})
}
note: I am considering respective parameters as an list of lists since multiple parameters should be passed to any one of the function , else if you have to pass only a single parameter to each then you can remove the spread operator.
注意:我将各个参数视为列表列表,因为应将多个参数传递给任何一个函数,否则如果您只需要向每个参数传递一个参数,则可以删除扩展运算符。
回答by Pedro Castilho
You could use Array.reduce.
你可以使用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());
Of course, this simplistic approach won't work if you have a promise which can error, or if you need previous results, so you might want to make sequencePromisesmore generic:
当然,如果您有一个可能出错的承诺,或者如果您需要以前的结果,这种简单的方法将不起作用,因此您可能想要sequencePromises更通用:
function genericSequencePromises(promiseFunction) {
return (promise, parameter) => {
return new Promise((resolve, reject) =>
return promiseFunction(resolve,
reject,
promise,
parameter));
}
}
Then you can do whatever you want as long as you return a Promise.
然后你可以做任何你想做的事,只要你返回一个 Promise。
Finally, you might benefit from this little helper:
最后,您可能会从这个小帮手中受益:
function promiseSeries(array, reducer) {
return array.reduce(reducer, Promise.resolve());
}
Bringing it all together:
把它放在一起:
let sequencePromises = genericSequencePromises((resolve, reject, promise, num) => {
resolve(promise.then(_ => console.log(`done: ${num}`)));
}
promiseSeries(myArray, sequencePromises);
This way, you can not only handle the case in your question, but much more complex cases.
这样,您不仅可以处理问题中的案例,还可以处理更复杂的案例。
回答by Master Chief
I know I am very late, and my answer is similar to what others have posted. But I thought I could post a clearer answer which may help any beginner.
我知道我很晚了,我的回答与其他人发布的相似。但我想我可以发布一个更清晰的答案,这可能对任何初学者都有帮助。
Instead of using promises directly, we can use promise factory. Since the promise starts executing as soon as they are created using promise factory we delay the creation of promise.
我们可以使用promise factory代替直接使用promise。由于承诺在使用承诺工厂创建后立即开始执行,因此我们延迟了承诺的创建。
In this example I create 5 which resolve after a second. I use a promiseCreator to create promises. Now the array promisesuses promiseCreatorto create 5 instances of promises. But array promiseFactorieswraps promiseCreatorin a function so promise is not invoked immediately. It is invoked when used.
在这个例子中,我创建了 5 秒后解析。我使用 promiseCreator 来创建承诺。现在该数组promises用于promiseCreator创建 5 个 Promise 实例。但是数组promiseFactories包装promiseCreator在一个函数中,因此不会立即调用 promise。它在使用时被调用。
Function executeSequentiallyexecutes all promiseLikesequentially.
函数executeSequentially全部promiseLike按顺序执行。
- When
promisearray is passed result ispromisearray itself executes parallely (actually they executed as soon as they are created, not when this line is called). - When
promiseFactoryarray is passed result is new Promise is created when earlier promise has completed their execution.
- 当
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)
回答by Yosvel Quintero Arguelles
You can iterate over the array of elements and pass the params like this:
您可以遍历元素数组并像这样传递参数:
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))
);
回答by Jason Livesay
I would use babeland do it this way:
我会使用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/[email protected]/babel.min.js"></script>

