我有一系列需要按顺序运行的承诺。
var promises = [promise1, promise2, ..., promiseN];
调用RSVP.all将并行执行它们:
RSVP.all(promises).then(...);
但是,我怎么能按顺序运行它们呢?
我可以像这样手动堆叠它们
RSVP.resolve()
.then(promise1)
.then(promise2)
...
.then(promiseN)
.then(...);
但问题是承诺的数量各不相同,承诺数组是动态建立的。
答案 0 :(得分:123)
如果你已经将它们放在一个数组中,那么它们就已经在执行了。如果你有一个承诺,那么它已经在执行。这不是承诺的关注(I.E在这方面它们不像C#Task
那样.Start()
方法。 .all
不会执行任何操作
它只是回报了一个承诺。
如果你有一系列承诺返回函数:
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
});
答案 1 :(得分:15)
答案 2 :(得分:5)
2017年的ES7方式。
tables.field
这将按顺序(逐个)执行给定的功能,而不是并行执行。参数 <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
。
使用上述代码的Plunker示例:http://plnkr.co/edit/UP0rhD?p=preview
答案 3 :(得分:4)
第二次尝试回答我试图更加解释:
首先,来自RSVP README:
的一些必要背景当您从第一个处理程序返回一个promise时,真正令人敬畏的部分就出现了......这可以让您平坦化嵌套的回调,并且是Promise的主要特性,它可以阻止具有大量异步代码的程序中的“向右漂移”
这正是你通过从应该在它之前完成的承诺的then
返回后来的承诺来顺序完成承诺的方式。
将这样的一组promise视为树是有帮助的,其中分支表示顺序进程,而叶表示并发进程。
构建这样一个承诺树的过程类似于构建其他种类树的常见任务:维护指针或引用树当前添加分支的位置,并迭代添加内容。
正如@Esailija在他的回答中指出的那样,如果你有一个不带参数的promise-returns函数数组,你可以使用reduce
为你整齐地构建树。如果你曾经为自己实现过reduce,你就会明白在@ Esailija的答案中幕后做的是减少是在保持对当前承诺(cur
)的引用并让每个承诺在其中返回下一个承诺then
。
如果你没有一个很好的齐次数组(关于他们采用/返回的参数)保证返回函数,或者如果你需要一个比简单线性序列更复杂的结构,你可以构造一个承诺树通过维护对promise树中要添加新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将多个“叶子”添加到promise“分支”,从而构建并发和顺序进程的组合。我的down for太复杂的答案就是一个例子。
您还可以使用Ember.run.scheduleOnce('afterRender')来确保在下一个承诺被触发之前呈现在一个承诺中完成的事情 - 我的downvoted-for-too-too-complex答案也显示了一个示例那个。
答案 4 :(得分:0)
我将在这里留下这个答案,因为当我来这里寻找解决问题的方法时,这对我有所帮助。
我追求的东西本质上是mapSeries ......我碰巧是映射保存在一组值上......我想要结果......
所以,据我所知,FWIW,以帮助其他人在将来搜索类似的东西......
(请注意,上下文是一个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);
}
});
答案 5 :(得分:0)
我有类似的问题,我做了一个递归函数,它按顺序逐个运行函数。
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([]);
};
答案 6 :(得分:0)
需要一切来解决这是一个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);
});
}
答案 7 :(得分:0)
另一种方法是在Promise
原型上定义全局 sequence 函数。
Promise.prototype.sequence = async function (promiseFns) {
for (let promiseFn of promiseFns) {
await promiseFn();
}
}
然后您可以在任何地方使用它,就像Promise.all()
示例
const timeout = async ms => {
return 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
免责声明:请谨慎编辑原型!
答案 8 :(得分:0)
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();
还可以将promise返回的内容存储在另一个私有var中,并将其传递给回调函数