การส่งผ่านอย่างชัดเจน
เช่นเดียวกับการซ้อนหมายเลขโทรกลับเทคนิคนี้อาศัยการปิด กระนั้นโซ่นั้นยังคงแบน - แทนที่จะส่งผ่านเฉพาะผลลัพธ์ล่าสุดวัตถุบางสถานะจะถูกส่งผ่านไปทุกขั้นตอน วัตถุสถานะเหล่านี้จะรวบรวมผลลัพธ์ของการกระทำก่อนหน้านี้โดยแจกค่าทั้งหมดที่จำเป็นในภายหลังอีกครั้งพร้อมกับผลลัพธ์ของงานปัจจุบัน
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
});
}
ที่นี่ลูกศรเล็ก ๆb => [resultA, b]
นั้นเป็นฟังก์ชั่นที่ปิดresultA
และส่งผ่านอาร์เรย์ของผลลัพธ์ทั้งสองไปยังขั้นตอนถัดไป ซึ่งใช้ไวยากรณ์การทำลายโครงสร้างพารามิเตอร์เพื่อแยกค่าในตัวแปรเดี่ยวอีกครั้ง
ก่อนที่จะมีการทำลายโครงสร้างพร้อมใช้งานกับ ES6 วิธีการช่วยเหลือที่ดีที่.spread()
ถูกเรียกใช้นั้นจัดทำโดยห้องสมุดสัญญาหลายแห่ง ( Q , Bluebird , เมื่อ , ... ) มันต้องใช้ฟังก์ชั่นที่มีหลายพารามิเตอร์ - หนึ่งสำหรับแต่ละองค์ประกอบอาร์เรย์ - .spread(function(resultA, resultB) { …
เพื่อนำมาใช้เป็น
แน่นอนว่าการปิดที่จำเป็นในที่นี้สามารถทำให้ง่ายขึ้นโดยฟังก์ชันผู้ช่วยบางอย่างเช่น
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));
หรือคุณสามารถใช้Promise.all
เพื่อสร้างคำสัญญาสำหรับอาร์เรย์:
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
});
}
และคุณอาจไม่เพียง แต่ใช้อาร์เรย์ แต่วัตถุที่ซับซ้อนโดยพลการ ตัวอย่างเช่นด้วย_.extend
หรือObject.assign
ในฟังก์ชั่นตัวช่วยที่แตกต่างกัน:
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
});
}
ในขณะที่รูปแบบนี้รับประกันโซ่แบนและวัตถุสถานะชัดเจนสามารถปรับปรุงความคมชัดมันจะกลายเป็นน่าเบื่อสำหรับสายยาว โดยเฉพาะอย่างยิ่งเมื่อคุณต้องการสถานะเป็นระยะ ๆ คุณยังต้องผ่านทุกขั้นตอน ด้วยอินเทอร์เฟซแบบคงที่นี้การโทรกลับครั้งเดียวในเครือจะค่อนข้างแน่นหนาและยืดหยุ่นไม่เปลี่ยนแปลง มันทำให้การแยกตัวออกจากขั้นตอนเดียวยากขึ้นและการโทรกลับไม่สามารถจัดหาได้โดยตรงจากโมดูลอื่น ๆ - พวกเขาจำเป็นต้องห่อด้วยรหัสสำเร็จรูปที่ใส่ใจเกี่ยวกับสถานะ ฟังก์ชั่นผู้ช่วยที่เป็นนามธรรมเช่นด้านบนสามารถลดความเจ็บปวดได้เล็กน้อย แต่จะมีอยู่เสมอ
javascript
แต่ก็มีความเกี่ยวข้องในภาษาอื่น ฉันใช้คำตอบ "break the chain"ใน java และjdeferred