根据问题的标题“一个接一个地(即顺序地)解决承诺?”,我们可以理解为OP更感兴趣的是对结算承诺的顺序处理,而不是顺序调用本身。
给出的答案是:
演示顺序调用对于响应的顺序处理是不必要的。
向本页的访问者展示可行的替代模式——包括OP,如果他在一年后仍然感兴趣的话。
尽管OP断言他不想同时拨打电话,这可能是真的,但同样也可能是基于标题所暗示的对连续处理响应的渴望的假设。
如果并发调用真的不需要,那么请参阅Benjamin Gruenbaum的回答,其中全面涵盖了顺序调用(等等)。
但是,如果您对允许并发调用然后依次处理响应的模式感兴趣(为了提高性能),那么请继续阅读。
你很容易认为你必须使用Promise.all(arr.map(fn)).then(fn)(我已经做过很多次了)或Promise库的花哨糖(尤其是Bluebird的),然而(这篇文章的功劳)arr.map(fn).reduce(fn)模式将完成这项工作,其优点是:
适用于任何承诺库——甚至是预兼容版本的jQuery——只使用.then()。
提供了灵活性,跳过错误或停止错误,无论你想用一行mod。
这就是,为Q写的。
var readFiles = function(files) {
return files.map(readFile) //Make calls in parallel.
.reduce(function(sequence, filePromise) {
return sequence.then(function() {
return filePromise;
}).then(function(file) {
//Do stuff with file ... in the correct sequence!
}, function(error) {
console.log(error); //optional
return sequence;//skip-over-error. To stop-on-error, `return error` (jQuery), or `throw error` (Promises/A+).
});
}, Q()).then(function() {
// all done.
});
};
注意:只有一个片段Q()是特定于Q的。对于jQuery,您需要确保readFile()返回jQuery承诺。有了A+,国外的承诺就会被同化。
这里的关键是还原的序列承诺,它对readFile承诺的处理进行排序,而不是对它们的创建进行排序。
一旦你理解了这一点,当你意识到.map()阶段实际上是不必要的时,可能会有点令人兴奋!整个工作,并行调用加上正确顺序的串行处理,可以通过reduce()单独实现,再加上进一步灵活的额外优势:
通过简单地移动一行,从并行异步调用转换为串行异步调用-在开发过程中可能有用。
这是Q。
var readFiles = function(files) {
return files.reduce(function(sequence, f) {
var filePromise = readFile(f);//Make calls in parallel. To call sequentially, move this line down one.
return sequence.then(function() {
return filePromise;
}).then(function(file) {
//Do stuff with file ... in the correct sequence!
}, function(error) {
console.log(error); //optional
return sequence;//Skip over any errors. To stop-on-error, `return error` (jQuery), or `throw error` (Promises/A+).
});
}, Q()).then(function() {
// all done.
});
};
这是基本模式。如果您还想向调用者交付数据(例如文件或它们的一些转换),则需要一个温和的变体。