如何按顺序执行承诺数组
How can I execute array of promises in sequential order?
我有一系列需要按顺序运行的承诺。
var promises = [promise1, promise2, ..., promiseN];
调用 RSVP.all 将并行执行它们:
RSVP.all(promises).then(...);
但是,如何按顺序运行它们?
我可以像这样手动堆叠它们
RSVP.resolve()
.then(promise1)
.then(promise2)
...
.then(promiseN)
.then(...);
但问题是承诺的数量各不相同,承诺的数组是动态构建的。
如果你已经在数组中拥有它们,那么它们已经在执行了。如果你有一个承诺,那么它已经在执行了。这不是承诺的问题(即它们在这方面不像 C# Task
.Start()
方法(。 .all
不执行任何内容它只是返回一个承诺。
如果你有一系列 promise 返回函数:
var tasks = [fn1, fn2, fn3...];
tasks.reduce(function(cur, next) {
return cur.then(next);
}, RSVP.resolve()).then(function() {
//all executed
});
或值:
var idsToDelete = [1,2,3];
idsToDelete.reduce(function(cur, next) {
return cur.then(function() {
return http.post("/delete.php?id=" + next);
});
}, RSVP.resolve()).then(function() {
//all executed
});
使用 ECMAScript 2017 异步函数,可以这样完成:
async function executeSequentially() {
const tasks = [fn1, fn2, fn3]
for (const fn of tasks) {
await fn();
}
}
你现在可以使用 BabelJS 来使用异步函数了
2017 年的 ES7 方式。
<script>
var funcs = [
_ => new Promise(resolve => setTimeout(_ => resolve("1"), 1000)),
_ => new Promise(resolve => setTimeout(_ => resolve("2"), 1000)),
_ => new Promise(resolve => setTimeout(_ => resolve("3"), 1000)),
_ => new Promise(resolve => setTimeout(_ => resolve("4"), 1000)),
_ => new Promise(resolve => setTimeout(_ => resolve("5"), 1000)),
_ => new Promise(resolve => setTimeout(_ => resolve("6"), 1000)),
_ => new Promise(resolve => setTimeout(_ => resolve("7"), 1000))
];
async function runPromisesInSequence(promises) {
for (let promise of promises) {
console.log(await promise());
}
}
</script>
<button onClick="runPromisesInSequence(funcs)">Do the thing</button>
这将按顺序(一个接一个(执行给定的函数,而不是并行执行。参数 promises
是一个函数数组,返回 Promise
。
使用上述代码的 Plunker 示例:http://plnkr.co/edit/UP0rhD?p=preview
另一种方法是在Promise
原型上定义全局序列函数。
Promise.prototype.sequence = async (promiseFns) => {
for (let promiseFn of promiseFns) {
await promiseFn();
}
}
然后你可以在任何地方使用它,就像Promise.all()
例
const timeout = async ms => new Promise(resolve =>
setTimeout(() => {
console.log("done", ms);
resolve();
}, ms)
);
// Executed one after the other
await Promise.sequence([() => timeout(1000), () => timeout(500)]);
// done: 1000
// done: 500
// Executed in parallel
await Promise.all([timeout(1000), timeout(500)]);
// done: 500
// done: 1000
免责声明:小心编辑原型!
第二次尝试回答,我试图在其中更具解释性:
首先,一些必要的背景,来自RSVP自述文件:
真正令人敬畏的部分是当您从第一个处理程序返回承诺时......这允许您平展嵌套回调,并且是承诺的主要功能,它可以防止具有大量异步代码的程序"向右漂移"。
这正是你使承诺按顺序排列的方式,通过从应该在它之前完成的承诺的then
返回后面的承诺。
将这样一组承诺视为一棵树是有帮助的,其中分支表示顺序进程,叶子表示并发进程。
构建这种承诺树的过程类似于构建其他类型的树的非常常见的任务:维护一个指针或引用,指向您当前在树中添加分支的位置,并迭代添加内容。
正如@Esailija在他的回答中指出的那样,如果你有一个不带参数的 promise 返回函数数组,你可以使用reduce
来整齐地为你构建树。如果你曾经为自己实现过reduce,你就会明白,在@Esailija的答案中,reduce在幕后所做的是保持对当前承诺(cur
(的引用,并让每个承诺在其then
中返回下一个承诺。
一个很好的齐次数组(关于它们接受/返回的参数(promise返回函数,或者如果你需要一个比简单线性序列更复杂的结构,你可以通过维护对promise树中你想要添加新promises的位置的引用来自己构造promise树:
var root_promise = current_promise = Ember.Deferred.create();
// you can also just use your first real promise as the root; the advantage of
// using an empty one is in the case where the process of BUILDING your tree of
// promises is also asynchronous and you need to make sure it is built first
// before starting it
current_promise = current_promise.then(function(){
return // ...something that returns a promise...;
});
current_promise = current_promise.then(function(){
return // ...something that returns a promise...;
});
// etc.
root_promise.resolve();
您可以使用 RSVP.all 构建并发和顺序进程的组合,以将多个"叶子"添加到承诺"分支"。我被否决的"过于复杂的答案"就是一个例子。
你也可以使用 Ember.run.scheduleOnce('afterRender'( 来确保在一个承诺中完成的事情在下一个承诺被触发之前被渲染——我被否决的太复杂答案也展示了一个例子。
解决这一问题只需要一个for
循环:)
var promises = [a,b,c];
var chain;
for(let i in promises){
if(chain) chain = chain.then(promises[i]);
if(!chain) chain = promises[i]();
}
function a(){
return new Promise((resolve)=>{
setTimeout(function(){
console.log('resolve A');
resolve();
},1000);
});
}
function b(){
return new Promise((resolve)=>{
setTimeout(function(){
console.log('resolve B');
resolve();
},500);
});
}
function c(){
return new Promise((resolve)=>{
setTimeout(function(){
console.log('resolve C');
resolve();
},100);
});
}
我遇到了类似的问题,我做了一个递归函数,它按顺序一个接一个地运行函数。
var tasks = [fn1, fn2, fn3];
var executeSequentially = function(tasks) {
if (tasks && tasks.length > 0) {
var task = tasks.shift();
return task().then(function() {
return executeSequentially(tasks);
});
}
return Promise.resolve();
};
如果您需要从这些函数收集输出:
var tasks = [fn1, fn2, fn3];
var executeSequentially = function(tasks) {
if (tasks && tasks.length > 0) {
var task = tasks.shift();
return task().then(function(output) {
return executeSequentially(tasks).then(function(outputs) {
outputs.push(output);
return Promise.resolve(outputs);
});
});
}
return Promise.resolve([]);
};
我追求的东西本质上是mapSeries,我碰巧在一组值上映射保存,我想要结果。
所以,据我所知,这是为了帮助其他人在未来搜索类似的东西。
(请注意,上下文是 Ember 应用程序(。
App = Ember.Application.create();
App.Router.map(function () {
// put your routes here
});
App.IndexRoute = Ember.Route.extend({
model: function () {
var block1 = Em.Object.create({save: function() {
return Em.RSVP.resolve("hello");
}});
var block2 = Em.Object.create({save: function() {
return Em.RSVP.resolve("this");
}});
var block3 = Em.Object.create({save: function() {
return Em.RSVP.resolve("is in sequence");
}});
var values = [block1, block2, block3];
// want to sequentially iterate over each, use reduce, build an array of results similarly to map...
var x = values.reduce(function(memo, current) {
var last;
if(memo.length < 1) {
last = current.save();
} else {
last = memo[memo.length - 1];
}
return memo.concat(last.then(function(results) {
return current.save();
}));
}, []);
return Ember.RSVP.all(x);
}
});
export type PromiseFn = () => Promise<any>;
export class PromiseSequence {
private fns: PromiseFn[] = [];
push(fn: PromiseFn) {
this.fns.push(fn)
}
async run() {
for (const fn of this.fns) {
await fn();
}
}
}
然后
const seq = new PromiseSequence();
seq.push(() => Promise.resolve(1));
seq.push(() => Promise.resolve(2));
seq.run();
也可以将承诺返回的内容存储在另一个私有 var 中并将其传递给回调
- Bluebird中承诺链数组的串行执行
- 如何按顺序执行承诺数组
- 角度 - 数组从承诺更新,整数不更新
- 链承诺.all 与从上一个承诺返回的数组.all.
- 链接返回承诺数组的函数
- 如何使用 Parse.promise javascript 定义一个承诺数组并获取结果数组 [parse.com]
- 实现时,将承诺数组转换为值数组
- Q.承诺数组,如果满足1个以上,则发出警报
- Node js没有解析承诺数组
- Emberjs拆分承诺数组
- 在AngularJS中向承诺数组中添加一个项
- 我如何从forEach循环中实现一个扁平的承诺数组?
- 动态推入$q.all()承诺数组
- 获取承诺数组的大小(量角器)
- 试图发送angular动态承诺数组来表示服务器
- 在承诺数组之间添加延迟
- 如何构造一个jquery承诺数组
- 用Angular UI Router解析承诺数组
- js承诺数组
- 使用'all'承诺数组上的聚合函数