ในระหว่างกระบวนการเขียน node.js การดำเนินการ IO อย่างต่อเนื่องอาจนำไปสู่ "Pyramid Nightmare" ฟังก์ชั่นการโทรกลับหลายครั้งทำให้รหัสยากที่จะรักษา คำสัญญาของ CommonJS ใช้ในการห่อหุ้มฟังก์ชั่นแบบอะซิงโครนัสและใช้ API โซ่แบบครบวงจรเพื่อกำจัดฝันร้ายของการโทรกลับหลายครั้ง
โมเดล IO ที่ไม่ปิดกั้นที่จัดทำโดย Node.js ช่วยให้เราสามารถใช้ฟังก์ชั่นการโทรกลับเพื่อจัดการการทำงานของ IO แต่เมื่อต้องการการดำเนินการ IO อย่างต่อเนื่องฟังก์ชั่นการโทรกลับของคุณจะซ้อนกันหลายครั้งรหัสไม่สวยงามและไม่ง่ายที่จะรักษาและอาจมีรหัสซ้ำหลายครั้ง
การคัดลอกรหัสมีดังนี้:
ขั้นตอนที่ 1 (ฟังก์ชั่น (ค่า 1) {
step2 (value1, function (value2) {
ขั้นตอนที่ 3 (value2, ฟังก์ชัน (value3) {
ขั้นตอนที่ 4 (ค่า 3, ฟังก์ชัน (value4) {
// ทำอะไรกับ Value4
-
-
-
-
นี่เป็นปัญหาของการควบคุมการไหลใน Node.js มีวิธีแก้ไขปัญหามากมายเช่นการใช้ Async, EventProxy ฯลฯ อย่างไรก็ตามหัวข้อของบทความนี้คือการใช้สัญญาในข้อกำหนด CommonJS เพื่อแก้ปัญหานี้
สัญญาคืออะไร?
มีข้อมูลจำเพาะสัญญาหลายประเภทสำหรับ CommonJs โดยทั่วไปเราจะหารือเกี่ยวกับข้อกำหนด/A+ A+ ซึ่งกำหนดพฤติกรรมพื้นฐานของสัญญา
สัญญาเป็นวัตถุที่มักจะแสดงถึงการดำเนินการแบบอะซิงโครนัสที่อาจเสร็จสมบูรณ์ในอนาคต การดำเนินการนี้อาจประสบความสำเร็จหรือล้มเหลวดังนั้นวัตถุสัญญาโดยทั่วไปมี 3 รัฐ: รอดำเนินการสำเร็จและปฏิเสธ มันแสดงให้เห็นถึงความสำเร็จและความล้มเหลวในการดำเนินงานที่ยังไม่เสร็จและประสบความสำเร็จตามลำดับ เมื่อสถานะของวัตถุสัญญาเปลี่ยนจากการรอดำเนินการเป็นทั้งที่ปฏิบัติตามหรือปฏิเสธสถานะของมันจะไม่สามารถเปลี่ยนแปลงได้อีกครั้ง
วัตถุสัญญามักจะมีวิธีการแล้วซึ่งช่วยให้เราสามารถใช้งานค่าที่ส่งคืนหลังจากความสำเร็จที่เป็นไปได้ในอนาคตหรือเหตุผลสำหรับความล้มเหลว วิธีนี้มีลักษณะเช่นนี้:
สัญญาแล้ว (onfulfilled, onrejected)
เห็นได้ชัดว่าวิธีการนั้นยอมรับพารามิเตอร์สองพารามิเตอร์ซึ่งมักจะเป็นสองฟังก์ชั่นหนึ่งใช้เพื่อประมวลผลผลลัพธ์หลังจากการดำเนินการสำเร็จและอื่น ๆ ใช้เพื่อประมวลผลสาเหตุของความล้มเหลวในการดำเนินการ พารามิเตอร์แรกของฟังก์ชั่นทั้งสองนี้เป็นผลลัพธ์หลังจากความสำเร็จและสาเหตุของความล้มเหลว หากวิธีการดังกล่าวไม่ใช่ฟังก์ชั่นพารามิเตอร์นี้จะถูกละเว้น
ค่าการส่งคืนของวิธีนี้เป็นวัตถุสัญญาซึ่งช่วยให้เราสามารถโทรออกจากนั้นเพื่อให้ได้ผลของการควบคุมกระบวนการ มีรายละเอียดมากมายที่นี่เช่นการถ่ายโอนค่าหรือการจัดการข้อผิดพลาด ข้อกำหนดของสัญญาถูกกำหนดเช่นนี้:
ค่าส่งคืนของฟังก์ชั่น onfulfilled หรือ onrejected ไม่ใช่วัตถุสัญญาจากนั้นค่าจะถูกใช้เป็นพารามิเตอร์แรกของ onfulfilled ในวิธีถัดไปจากนั้น หากค่าส่งคืนเป็นวัตถุสัญญาค่าส่งคืนของวิธีนั้นจะเป็นวัตถุสัญญาได้อย่างไร
หากข้อยกเว้นถูกโยนลงไปในฟังก์ชัน onfulfilled หรือ onrejected สถานะของวัตถุวิธีการที่ส่งคืนนั้นจะถูกแปลงเป็นปฏิเสธ หากการเรียกวัตถุสัญญาจากนั้นวัตถุข้อผิดพลาดจะถูกใช้เป็นพารามิเตอร์แรกของฟังก์ชัน onrejected
หากรัฐสัญญาสำเร็จและฟังก์ชั่น onfulfilled ไม่ได้ระบุไว้ในวิธีการดังกล่าวสถานะวัตถุสัญญาที่ส่งคืนโดยวิธีการดังกล่าวจะสำเร็จและผลลัพธ์ที่ประสบความสำเร็จเป็นผลมาจากสัญญาก่อนหน้านี้จะเป็นจริงสำหรับการปฏิเสธ
เพื่อเพิ่มทั้ง onfulfilled และ onrejected จะถูกดำเนินการแบบอะซิงโครนัส
การดำเนินการตามข้อกำหนด: Q
ข้างต้นเป็นเรื่องเกี่ยวกับข้อกำหนดของสัญญาและสิ่งที่เราต้องการคือการดำเนินการ Q เป็นห้องสมุดที่มีข้อกำหนดการใช้งานที่ดีกว่าสำหรับ Promise/A+
ก่อนอื่นเราต้องสร้างวัตถุสัญญา ข้อกำหนดสำหรับการสร้างวัตถุสัญญาอยู่ในสัญญา/b ฉันจะไม่อธิบายรายละเอียดที่นี่เพียงเพิ่มรหัส
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น (ธง) {
var defer = q.defer ();
fs.readfile ("a.txt", ฟังก์ชั่น (err, data) {
ถ้า (err) defer.reject (err);
else defer.resolve (ข้อมูล);
-
กลับมาเลื่อนเวลา;
-
การดำเนินการตามสัญญาส่วนใหญ่มีความคล้ายคลึงกันในการสร้างสัญญา โดยการสร้างวัตถุเลื่อนเวลาด้วยแอตทริบิวต์สัญญาหากได้รับค่าสำเร็จจะเรียกว่า defer.resolve (ค่า) จะเรียกว่าถ้ามันล้มเหลวให้ defer.reject (เหตุผล) เรียกและในที่สุดก็ส่งคืนแอตทริบิวต์สัญญาของการเลื่อนเวลา กระบวนการนี้สามารถเข้าใจได้ว่าเป็นการเรียกร้องให้เลื่อนเวลาออกไปเปลี่ยนสถานะของสัญญาให้สำเร็จและการโทรออกการปฏิเสธจะเปลี่ยนสถานะของสัญญาให้ถูกปฏิเสธ
เมื่อเผชิญกับวิธีการแบบอะซิงโครนัสอย่างต่อเนื่องคุณจะเขียนโค้ดที่สวยงามโดยใช้สัญญาได้อย่างไร? ดูตัวอย่างต่อไปนี้
การคัดลอกรหัสมีดังนี้:
Promise0. แล้ว (ฟังก์ชั่น (ผลลัพธ์) {
// dosomething
ผลการกลับมา;
}). จากนั้น (ฟังก์ชั่น (ผลลัพธ์) {
// dosomething
กลับมาสัญญา 1;
}). จากนั้น (ฟังก์ชั่น (ผลลัพธ์) {
// dosomething
}). catch (ฟังก์ชั่น (ex) {
console.log (ex);
- ในที่สุด (function () {
console.log ("สุดท้าย");
-
ในรหัสข้างต้นวิธีนี้จะยอมรับเฉพาะ onfulfilled และวิธีการจับนั้นเป็นจริง ด้วยวิธีนี้ตราบใดที่ชุดของวิธีการแบบอะซิงโครนัสมักจะส่งคืนค่าให้ประสบความสำเร็จรหัสจะวิ่งลงในสไตล์น้ำตก หากวิธีการแบบอะซิงโครนัสใด ๆ ล้มเหลวหรือมีข้อยกเว้นเกิดขึ้นตามข้อกำหนดของ CommonJS Promise ฟังก์ชันในการจับจะถูกดำเนินการ Q ยังมีวิธีการในที่สุดซึ่งง่ายต่อการเข้าใจอย่างแท้จริงนั่นคือไม่ว่าจะแก้ไขหรือปฏิเสธฟังก์ชั่นในที่สุดจะถูกดำเนินการ
มันดูดีรหัสได้รับการดูแลและสวยงามมากขึ้นดังนั้นถ้าคุณต้องการพร้อมกันล่ะ?
การคัดลอกรหัสมีดังนี้:
Q.All ([Promise0, Promise1, Promise2]). Spread (ฟังก์ชั่น (val0, val1, val2) {
console.log (อาร์กิวเมนต์);
}). จากนั้น (ฟังก์ชัน () {
console.log ("เสร็จสิ้น");
}). catch (ฟังก์ชั่น (err) {
console.log (err);
-
Q ยังมี API สำหรับการเกิดขึ้นพร้อมกันการเรียกวิธีการทั้งหมดและผ่านอาร์เรย์สัญญาสามารถใช้สไตล์โซ่ของนั้นต่อไปได้ นอกจากนี้ยังมีสิ่งที่ดีเช่น Q.NFBIND ฯลฯ ที่สามารถแปลง API ดั้งเดิมของ Node.js ให้เป็นสัญญาที่จะรวมรูปแบบรหัส API เพิ่มเติมจะไม่ได้รับการอธิบายในรายละเอียดที่นี่
สรุปแล้ว
บทความนี้ส่วนใหญ่แนะนำการใช้สัญญาเพื่อแก้ปัญหาการไหลของ Node.js แต่สัญญายังสามารถนำไปใช้กับส่วนหน้าได้ Emcascript6 ได้ให้การสนับสนุน API ดั้งเดิม มันควรจะชี้ให้เห็นว่าสัญญาไม่ใช่ทางออกเดียว Async ก็เป็นตัวเลือกที่ดีและให้ API ควบคุมพร้อมกันที่เป็นมิตรมากขึ้น แต่ฉันคิดว่าสัญญามีข้อได้เปรียบมากขึ้นเมื่อฟังก์ชั่นการห่อหุ้มด้วยวิธีการแบบอะซิงโครนัส
โอเคนั่นคือทั้งหมดสำหรับบทความนี้ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน