คำสัญญาที่ชัดเจนในการก่อสร้างรูปแบบการก่อสร้างคืออะไรและฉันจะหลีกเลี่ยงได้อย่างไร
ฉันกำลังเขียนโค้ดที่ทำสิ่งที่ดูเหมือน:
function getStuffDone(param) { | function getStuffDone(param) {
var d = Q.defer(); /* or $q.defer */ | return new Promise(function(resolve, reject) {
// or = new $.Deferred() etc. | // using a promise constructor
myPromiseFn(param+1) | myPromiseFn(param+1)
.then(function(val) { /* or .done */ | .then(function(val) {
d.resolve(val); | resolve(val);
}).catch(function(err) { /* .fail */ | }).catch(function(err) {
d.reject(err); | reject(err);
}); | });
return d.promise; /* or promise() */ | });
} | }
มีคนบอกฉันนี้จะเรียกว่า " antipattern รอการตัดบัญชี " หรือ " Promise
คอนสตรัค antipattern " ตามลำดับสิ่งที่ไม่ดีเกี่ยวกับรหัสนี้และทำไมนี้เรียกantipattern ?
คำตอบ
รูปแบบการต่อต้านที่รอการตัดบัญชี (ปัจจุบันคือรูปแบบการต่อต้านการก่อสร้างอย่างชัดเจน) ที่Esailijaประกาศเกียรติคุณเป็นคนต่อต้านรูปแบบทั่วไปที่ยังใหม่ต่อคำสัญญาฉันได้ทำด้วยตัวเองเมื่อฉันใช้สัญญา ปัญหาเกี่ยวกับรหัสข้างต้นคือไม่สามารถใช้ประโยชน์จากความจริงที่เป็นห่วงโซ่สัญญาได้
คำสัญญาสามารถเชื่อมโยงกับ.then
และคุณสามารถคืนสัญญาได้โดยตรง รหัสของคุณในgetStuffDone
สามารถเขียนใหม่เป็น:
function getStuffDone(param){
return myPromiseFn(param+1); // much nicer, right?
}
สัญญาเป็นข้อมูลเกี่ยวกับการทำให้โค้ดอะซิงโครนัสสามารถอ่านได้มากขึ้นและทำตัวเหมือนโค้ดซิงโครนัสโดยไม่ซ่อนความจริงนั้น คำสัญญาเป็นตัวแทนของสิ่งที่เป็นนามธรรมมากกว่าคุณค่าของการดำเนินการเพียงครั้งเดียวซึ่งเป็นนามธรรมแนวคิดของคำสั่งหรือนิพจน์ในภาษาโปรแกรม
คุณควรใช้ออบเจ็กต์ที่รอการตัดบัญชีเฉพาะเมื่อคุณกำลังแปลง API เป็นสัญญาและไม่สามารถทำได้โดยอัตโนมัติหรือเมื่อคุณเขียนฟังก์ชันการรวมที่แสดงด้วยวิธีนี้ได้ง่ายขึ้น
อ้างถึง Esailija:
นี่คือรูปแบบการต่อต้านที่พบบ่อยที่สุด เป็นเรื่องง่ายที่จะตกอยู่ในสิ่งนี้เมื่อคุณไม่เข้าใจคำสัญญาจริงๆและคิดว่าพวกเขาเป็นตัวปล่อยเหตุการณ์ที่ได้รับการยกย่องหรือยูทิลิตี้เรียกกลับ สรุป: คำสัญญาเกี่ยวกับการสร้างรหัสอะซิงโครนัสรักษาคุณสมบัติส่วนใหญ่ที่หายไปของรหัสซิงโครนัสเช่นการเยื้องแบบแบนและช่องทางยกเว้นหนึ่งช่อง
มันผิดอะไร?
แต่ลายใช้ได้!
โชคดีนะคุณ. น่าเสียดายที่อาจไม่เป็นเช่นนั้นอย่างที่คุณอาจลืมขอบบางส่วนไป มากกว่าครึ่งหนึ่งของเหตุการณ์ที่ฉันเคยเห็นผู้เขียนลืมที่จะดูแลตัวจัดการข้อผิดพลาด:
return new Promise(function(resolve) {
getOtherPromise().then(function(result) {
resolve(result.property.example);
});
})
หากคำสัญญาอื่นถูกปฏิเสธสิ่งนี้จะเกิดขึ้นโดยไม่มีใครสังเกตเห็นแทนที่จะแพร่กระจายไปยังคำสัญญาใหม่ (ซึ่งจะได้รับการจัดการ) - และสัญญาใหม่จะรอดำเนินการตลอดไปซึ่งอาจทำให้เกิดการรั่วไหล
สิ่งเดียวกันนี้เกิดขึ้นในกรณีที่รหัสโทรกลับของคุณทำให้เกิดข้อผิดพลาดเช่นเมื่อresult
ไม่มีproperty
และมีข้อยกเว้นเกิดขึ้น นั่นจะไม่สามารถจัดการได้และปล่อยให้คำสัญญาใหม่ไม่ได้รับการแก้ไข
ในทางตรงกันข้ามการใช้.then()
จะดูแลสถานการณ์ทั้งสองนี้โดยอัตโนมัติและปฏิเสธคำสัญญาใหม่เมื่อเกิดข้อผิดพลาด:
return getOtherPromise().then(function(result) {
return result.property.example;
})
แอนติแพตเทิร์นรอการตัดบัญชีไม่เพียง แต่ยุ่งยาก แต่ยังเกิดข้อผิดพลาดอีกด้วย การใช้.then()
โซ่จะปลอดภัยกว่ามาก
แต่ฉันจัดการทุกอย่างแล้ว!
จริงๆ? ดี. อย่างไรก็ตามสิ่งนี้จะมีรายละเอียดและมีจำนวนมากโดยเฉพาะอย่างยิ่งหากคุณใช้ไลบรารีสัญญาที่รองรับคุณสมบัติอื่น ๆ เช่นการยกเลิกหรือการส่งข้อความ หรืออาจจะในอนาคตหรือคุณต้องการเปลี่ยนห้องสมุดของคุณกับห้องสมุดที่ดีกว่า คุณไม่ต้องการเขียนโค้ดของคุณใหม่สำหรับสิ่งนั้น
วิธีการของไลบรารี ( then
) ไม่เพียง แต่รองรับคุณสมบัติทั้งหมด แต่ยังอาจมีการเพิ่มประสิทธิภาพบางอย่าง การใช้สิ่งเหล่านี้มีแนวโน้มที่จะทำให้โค้ดของคุณเร็วขึ้นหรืออย่างน้อยก็อนุญาตให้มีการปรับให้เหมาะสมโดยการแก้ไขในอนาคตของไลบรารี
ฉันจะหลีกเลี่ยงได้อย่างไร
ดังนั้นเมื่อใดก็ตามที่คุณพบว่าตัวเองด้วยตนเองสร้างPromise
หรือDeferred
แล้วและสัญญาที่มีอยู่มีความเกี่ยวข้องกับการตรวจสอบ API ห้องสมุดแรก antipattern รอตัดบัญชีมักจะถูกนำไปใช้โดยคนที่เห็นสัญญา [เท่านั้น] เป็นรูปแบบการสังเกตการณ์ - แต่สัญญาที่มีมากขึ้นกว่าการเรียกกลับพวกเขาควรจะเป็น composable ห้องสมุดที่ดีทุกแห่งมีฟังก์ชั่นที่ใช้งานง่ายมากมายสำหรับการจัดองค์ประกอบของคำสัญญาในทุก ๆ ลักษณะที่น่าคิดโดยดูแลทุกสิ่งระดับต่ำที่คุณไม่ต้องการจัดการ
หากคุณพบว่าจำเป็นต้องเขียนคำสัญญาด้วยวิธีใหม่ที่ฟังก์ชันตัวช่วยที่มีอยู่ไม่รองรับการเขียนฟังก์ชันของคุณเองโดยมีการรอการตัดบัญชีที่หลีกเลี่ยงไม่ได้ควรเป็นทางเลือกสุดท้ายของคุณ ลองเปลี่ยนไปใช้ไลบรารีที่มีคุณลักษณะมากขึ้นและ / หรือแจ้งข้อบกพร่องกับไลบรารีปัจจุบันของคุณ ผู้ดูแลรักษาควรสามารถรับองค์ประกอบจากฟังก์ชันที่มีอยู่ใช้ฟังก์ชันตัวช่วยใหม่สำหรับคุณและ / หรือช่วยระบุกรณีขอบที่ต้องจัดการ