Виходячи з заголовка питання, "Вирішувати обіцянки одна за одною (тобто послідовно)?", Ми можемо зрозуміти, що ОП більше зацікавлена в послідовній обробці обіцянок щодо врегулювання, ніж послідовних дзвінках як такої .
Ця відповідь пропонується:
- щоб продемонструвати, що послідовні дзвінки не потрібні для послідовного опрацювання відповідей.
- розкрити для відвідувачів цієї сторінки життєздатні альтернативні зразки, включаючи ОП, якщо він все ще зацікавився через рік.
- незважаючи на твердження ОП, що він не хоче одночасно телефонувати на дзвінки, що справді може бути справді, але однаково може бути припущенням, заснованим на прагненні до послідовної обробки відповідей, як випливає з назви.
Якщо одночасні дзвінки справді не потрібні, то дивіться відповідь Бенджаміна Грюнбаума, який охоплює послідовні дзвінки (тощо) всебічно.
Якщо ви зацікавлені (для підвищення продуктивності) у моделях, які дозволяють одночасно приймати дзвінки з подальшим послідовним обробкою відповідей, тоді читайте далі.
Привабливо подумати, що вам доведеться використовувати Promise.all(arr.map(fn)).then(fn)
(як я це робив багато разів) або фантазійний цукор "Обіцяючої губки" (особливо Bluebird), однак (з урахуванням цієї статті ) arr.map(fn).reduce(fn)
модель зробить цю роботу, з перевагами, які вона:
- працює з будь-якою ланкою для обіцянок - використовується навіть попередня версія jQuery
.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 + lib, іноземні обіцянки будуть засвоєні.
Ключовий момент тут є скороченням в 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.
});
};
Це основна закономірність. Якщо ви також хотіли доставити дані (наприклад, файли або перетворення їх) абоненту, вам знадобиться м'який варіант.