คำสัญญาที่ชัดเจนในการก่อสร้างรูปแบบการก่อสร้างคืออะไรและฉันจะหลีกเลี่ยงได้อย่างไร

May 22 2014

ฉันกำลังเขียนโค้ดที่ทำสิ่งที่ดูเหมือน:

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 ?

คำตอบ

380 BenjaminGruenbaum May 22 2014 at 17:07

รูปแบบการต่อต้านที่รอการตัดบัญชี (ปัจจุบันคือรูปแบบการต่อต้านการก่อสร้างอย่างชัดเจน) ที่Esailijaประกาศเกียรติคุณเป็นคนต่อต้านรูปแบบทั่วไปที่ยังใหม่ต่อคำสัญญาฉันได้ทำด้วยตัวเองเมื่อฉันใช้สัญญา ปัญหาเกี่ยวกับรหัสข้างต้นคือไม่สามารถใช้ประโยชน์จากความจริงที่เป็นห่วงโซ่สัญญาได้

คำสัญญาสามารถเชื่อมโยงกับ.thenและคุณสามารถคืนสัญญาได้โดยตรง รหัสของคุณในgetStuffDoneสามารถเขียนใหม่เป็น:

function getStuffDone(param){
    return myPromiseFn(param+1); // much nicer, right?
}

สัญญาเป็นข้อมูลเกี่ยวกับการทำให้โค้ดอะซิงโครนัสสามารถอ่านได้มากขึ้นและทำตัวเหมือนโค้ดซิงโครนัสโดยไม่ซ่อนความจริงนั้น คำสัญญาเป็นตัวแทนของสิ่งที่เป็นนามธรรมมากกว่าคุณค่าของการดำเนินการเพียงครั้งเดียวซึ่งเป็นนามธรรมแนวคิดของคำสั่งหรือนิพจน์ในภาษาโปรแกรม

คุณควรใช้ออบเจ็กต์ที่รอการตัดบัญชีเฉพาะเมื่อคุณกำลังแปลง API เป็นสัญญาและไม่สามารถทำได้โดยอัตโนมัติหรือเมื่อคุณเขียนฟังก์ชันการรวมที่แสดงด้วยวิธีนี้ได้ง่ายขึ้น

อ้างถึง Esailija:

นี่คือรูปแบบการต่อต้านที่พบบ่อยที่สุด เป็นเรื่องง่ายที่จะตกอยู่ในสิ่งนี้เมื่อคุณไม่เข้าใจคำสัญญาจริงๆและคิดว่าพวกเขาเป็นตัวปล่อยเหตุการณ์ที่ได้รับการยกย่องหรือยูทิลิตี้เรียกกลับ สรุป: คำสัญญาเกี่ยวกับการสร้างรหัสอะซิงโครนัสรักษาคุณสมบัติส่วนใหญ่ที่หายไปของรหัสซิงโครนัสเช่นการเยื้องแบบแบนและช่องทางยกเว้นหนึ่งช่อง

142 Bergi Aug 29 2014 at 20:28

มันผิดอะไร?

แต่ลายใช้ได้!

โชคดีนะคุณ. น่าเสียดายที่อาจไม่เป็นเช่นนั้นอย่างที่คุณอาจลืมขอบบางส่วนไป มากกว่าครึ่งหนึ่งของเหตุการณ์ที่ฉันเคยเห็นผู้เขียนลืมที่จะดูแลตัวจัดการข้อผิดพลาด:

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 ห้องสมุดที่ดีทุกแห่งมีฟังก์ชั่นที่ใช้งานง่ายมากมายสำหรับการจัดองค์ประกอบของคำสัญญาในทุก ๆ ลักษณะที่น่าคิดโดยดูแลทุกสิ่งระดับต่ำที่คุณไม่ต้องการจัดการ

หากคุณพบว่าจำเป็นต้องเขียนคำสัญญาด้วยวิธีใหม่ที่ฟังก์ชันตัวช่วยที่มีอยู่ไม่รองรับการเขียนฟังก์ชันของคุณเองโดยมีการรอการตัดบัญชีที่หลีกเลี่ยงไม่ได้ควรเป็นทางเลือกสุดท้ายของคุณ ลองเปลี่ยนไปใช้ไลบรารีที่มีคุณลักษณะมากขึ้นและ / หรือแจ้งข้อบกพร่องกับไลบรารีปัจจุบันของคุณ ผู้ดูแลรักษาควรสามารถรับองค์ประกอบจากฟังก์ชันที่มีอยู่ใช้ฟังก์ชันตัวช่วยใหม่สำหรับคุณและ / หรือช่วยระบุกรณีขอบที่ต้องจัดการ