Исходя из названия вопроса: «Решение обещает одно за другим (то есть в последовательности)?», мы могли бы понять, что ОП больше интересуется последовательной обработкой обещаний по расчету, чем последовательными вызовами per se .
Этот ответ предлагается:
Если одновременные вызовы действительно не нужны, см. ответ Бенджамина Грюнбаума, который охватывает последовательные вызовы (и т. д.) всесторонне.
Если, однако, вы заинтересованы (для повышения производительности) в шаблонах, которые допускают одновременные вызовы, за которыми следует последовательная обработка ответов, тогда, пожалуйста, прочитайте.
Заманчиво думать, что вам нужно использовать Promise.all(arr.map(fn)).then(fn)
(как я делал много раз), или саунд-мотив Promise lib (особенно Bluebird's), однако (с учетом этой статьи ) шаблон arr.map(fn).reduce(fn)
выполнит это задание с теми преимуществами, которые он имеет:
.then()
. Здесь он написан для 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 + libs будут усваиваться иностранные обещания.
Ключевым моментом является обещание сокращения sequence
, в котором последовательности обработки 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.
});
};
Это базовый шаблон. Если вы захотите также предоставить данные (например, файлы или некоторые их преобразования) вызывающему, вам понадобится мягкий вариант.