Atas dasar judul pertanyaan, "Selesaikan satu demi satu janji (yaitu secara berurutan)?", Kita mungkin memahami bahwa OP lebih tertarik pada penanganan berurutan janji pada penyelesaian daripada panggilan berurutan per se .
Jawaban ini ditawarkan:
- untuk menunjukkan bahwa panggilan berurutan tidak diperlukan untuk penanganan respons berurutan.
- untuk mengekspos pola alternatif yang layak untuk pengunjung halaman ini - termasuk OP jika dia masih tertarik lebih dari setahun kemudian.
- terlepas dari pernyataan OP bahwa dia tidak ingin melakukan panggilan secara bersamaan, yang mungkin benar-benar terjadi tetapi sama-sama dapat menjadi asumsi berdasarkan keinginan untuk penanganan tanggapan berurutan sesuai dengan judulnya.
Jika panggilan bersamaan benar-benar tidak diinginkan maka lihat jawaban Benjamin Gruenbaum yang mencakup panggilan berurutan (dll) secara komprehensif.
Namun, jika Anda tertarik (untuk peningkatan kinerja) dalam pola yang memungkinkan panggilan serentak diikuti dengan penanganan respons berurutan, maka silakan baca terus.
Sangat menggoda untuk berpikir Anda harus menggunakan Promise.all(arr.map(fn)).then(fn)
(seperti yang telah saya lakukan berkali-kali) atau gula mewah lib Promise (terutama Bluebird), namun (dengan kredit untuk artikel ini ) sebuah arr.map(fn).reduce(fn)
pola akan melakukan pekerjaan, dengan keuntungan bahwa:
- bekerja dengan sembarang janji - bahkan versi jQuery yang sesuai sebelumnya - hanya
.then()
digunakan.
- memberikan fleksibilitas untuk melewatkan kesalahan atau menghentikan kesalahan, mana pun yang Anda inginkan dengan mod satu baris.
Ini dia, ditulis untuk 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.
});
};
Catatan: hanya satu fragmen itu, Q()
yang khusus untuk Q. Untuk jQuery Anda harus memastikan bahwa readFile () mengembalikan janji jQuery. Dengan A + libs, janji-janji asing akan berasimilasi.
Kuncinya di sini adalah pengurangan ini sequence
janji, yang sekuens yang penanganan darireadFile
janji janji tetapi bukan penciptaannya.
Dan begitu Anda menyerapnya, mungkin sedikit mengejutkan ketika Anda menyadari bahwa .map()
panggung sebenarnya tidak diperlukan! Seluruh pekerjaan, panggilan paralel ditambah penanganan serial dalam urutan yang benar, dapat dicapai dengan reduce()
sendirian, ditambah keuntungan tambahan dari fleksibilitas lebih lanjut untuk:
- mengkonversi dari panggilan async paralel ke panggilan async serial dengan hanya memindahkan satu baris - berpotensi berguna selama pengembangan.
Ini dia, untuk Q
lagi.
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.
});
};
Itulah pola dasarnya. Jika Anda juga ingin mengirimkan data (misalnya file atau beberapa transformasi) ke pemanggil, Anda memerlukan varian yang ringan.