第二次尝试回答,我试图在其中更具解释性:
首先,一些必要的背景,来自RSVP README:
当您从第一个处理程序返回Promise时,真正令人敬畏的部分出现了......这允许您扁平化嵌套的回调,并且是Promise的主要功能,可以防止在具有大量异步代码的程序中“向右漂移”。
这正是你如何按顺序进行Promise,通过从then
应该在它之前完成的Promise中返回后面的Promise。
将这样的一组 promise 视为一棵树,其中分支代表顺序进程,而叶子代表并发进程,这会很有帮助。
构建这样一棵 Promise 树的过程类似于构建其他类型树的非常常见的任务:维护指向当前在树中添加分支的位置的指针或引用,并迭代地添加内容。
正如@Esailija 在他的回答中指出的那样,如果您有一组不带参数的Promise返回函数,您可以用来reduce
为您整齐地构建树。如果您曾经为自己实现过 reduce,您就会明白在@Esailja 的回答中,reduce 在幕后所做的是维护对当前Promise ( cur
)的引用,并让每个Promise返回其then
.
如果你没有一个很好的同构数组(关于它们接受/返回的参数)Promise返回函数,或者如果你需要一个比简单线性序列更复杂的结构,你可以通过维护自己构建Promise树对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“分支”添加多个“叶子”来构建并发和顺序进程的组合。我因过于复杂而被低估的答案显示了一个例子。
您还可以使用 Ember.run.scheduleOnce('afterRender') 来确保在一个Promise中完成的某些事情在下一个Promise被触发之前被渲染——我的反对票太复杂的答案也显示了一个例子。