Pass-through eksplisit
Mirip dengan bersarangnya callback, teknik ini bergantung pada penutupan. Namun, rantai tetap datar - alih-alih hanya melewati hasil terbaru, beberapa objek negara dilewatkan untuk setiap langkah. Objek keadaan ini mengakumulasikan hasil dari tindakan sebelumnya, menyerahkan semua nilai yang akan dibutuhkan nanti ditambah hasil dari tugas saat ini.
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return promiseB(…).then(b => [resultA, b]); // function(b) { return [resultA, b] }
}).then(function([resultA, resultB]) {
// more processing
return // something using both resultA and resultB
});
}
Di sini, panah kecil itu b => [resultA, b]
adalah fungsi yang menutup resultA
, dan meneruskan array dari kedua hasil ke langkah berikutnya. Yang menggunakan sintaksis perusak parameter untuk memecahnya dalam variabel tunggal lagi.
Sebelum penghancuran tersedia dengan ES6, metode pembantu yang bagus disebut .spread()
disediakan oleh banyak perpustakaan janji ( Q , Bluebird , kapan , ...). Dibutuhkan fungsi dengan beberapa parameter - satu untuk setiap elemen array - untuk digunakan sebagai .spread(function(resultA, resultB) { …
.
Tentu saja, penutupan yang diperlukan di sini dapat lebih disederhanakan oleh beberapa fungsi pembantu, misalnya
function addTo(x) {
// imagine complex `arguments` fiddling or anything that helps usability
// but you get the idea with this simple one:
return res => [x, res];
}
…
return promiseB(…).then(addTo(resultA));
Atau, Anda dapat menggunakan Promise.all
untuk menghasilkan janji untuk array:
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return Promise.all([resultA, promiseB(…)]); // resultA will implicitly be wrapped
// as if passed to Promise.resolve()
}).then(function([resultA, resultB]) {
// more processing
return // something using both resultA and resultB
});
}
Dan Anda mungkin tidak hanya menggunakan array, tetapi objek kompleks yang sewenang-wenang. Misalnya, dengan _.extend
atau Object.assign
dalam fungsi pembantu yang berbeda:
function augment(obj, name) {
return function (res) { var r = Object.assign({}, obj); r[name] = res; return r; };
}
function getExample() {
return promiseA(…).then(function(resultA) {
// some processing
return promiseB(…).then(augment({resultA}, "resultB"));
}).then(function(obj) {
// more processing
return // something using both obj.resultA and obj.resultB
});
}
Sementara pola ini menjamin rantai datar dan objek keadaan eksplisit dapat meningkatkan kejelasan, itu akan menjadi membosankan untuk rantai panjang. Terutama ketika Anda membutuhkan negara hanya secara sporadis, Anda masih harus melewati setiap langkah. Dengan antarmuka tetap ini, panggilan balik tunggal dalam rantai agak erat digabungkan dan tidak fleksibel untuk diubah. Itu membuat anjak keluar satu langkah lebih sulit, dan callback tidak dapat dipasok langsung dari modul lain - mereka selalu harus dibungkus dengan kode boilerplate yang peduli dengan keadaan. Fungsi pembantu abstrak seperti di atas dapat sedikit meredakan rasa sakit, tetapi akan selalu ada.
javascript
, itu relevan dalam bahasa lain. Saya hanya menggunakan jawaban "break the chain" di java dan jdeferred