การเขียนโปรแกรมแบบซิงโครนัสโดยทั่วไปนั้นง่ายต่อการดีบักและบำรุงรักษาอย่างไรก็ตามการเขียนโปรแกรมแบบอะซิงโครนัสโดยทั่วไปจะให้ประสิทธิภาพที่ดีขึ้นและมีความยืดหยุ่นมากขึ้น คุณสมบัติที่ใหญ่ที่สุดของอะซิงโครนัสคือไม่จำเป็นต้องรอ "สัญญา" ค่อยๆกลายเป็นส่วนสำคัญที่สุดของ JavaScript และ API ใหม่จำนวนมากได้เริ่มใช้หลักการสัญญา มาดูกันว่าสัญญาคืออะไรและ API และการใช้งาน!
สถานะสัญญา
XMLHTTPREQUEST API เป็นแบบอะซิงโครนัส แต่ไม่ได้ใช้ API สัญญา แต่มี API JavaScript ดั้งเดิมจำนวนมากที่ใช้สัญญา:
*แบตเตอรี่ API
*Fetch API (การแทนที่ XHR)
*ผู้ให้บริการ API
สัญญาจะกลายเป็นที่นิยมและเป็นเรื่องธรรมดามากขึ้นในอนาคตและเป็นสิ่งสำคัญมากที่นักพัฒนาส่วนหน้าทุกคนจะใช้มัน อีกสิ่งหนึ่งที่น่าสังเกตก็คือ Node.js เป็นแพลตฟอร์มตามสัญญา (เห็นได้ชัดว่าสัญญาเป็นคุณลักษณะหลักของมัน)
การใช้สัญญานั้นง่ายกว่าที่คุณคิด - ถ้าคุณเคยใช้ Settimeout เพื่อควบคุมงานอะซิงโครนัส!
การใช้สัญญาขั้นพื้นฐาน
ตัวสร้างสัญญาใหม่ () สามารถใช้ในงานแบบอะซิงโครนัสแบบดั้งเดิมเช่นเดียวกับการใช้งานก่อนหน้านี้ของ Settimeout และ XMLHTTPREQUEST สัญญาใหม่ถูกสร้างขึ้นโดยใช้คำหลักใหม่ ในเวลาเดียวกันสัญญานี้ให้การแก้ไขและปฏิเสธฟังก์ชั่นเพื่อให้เราสามารถดำเนินการโทรกลับ:
var p = สัญญาใหม่ (ฟังก์ชั่น (แก้ไข, ปฏิเสธ) {// ทำภารกิจ async async งานแล้ว ... ถ้า (/ * เงื่อนไขที่ดี */) {แก้ไข ('ความสำเร็จ!');} else {ปฏิเสธ ('ล้มเหลว!');}});โปรแกรมเมอร์สามารถเรียกใช้การแก้ไขและปฏิเสธฟังก์ชั่นภายในฟังก์ชั่นการโทรกลับตามสถานการณ์การดำเนินการ นี่คือตัวอย่างที่สมจริงยิ่งขึ้นที่แปลงการโทร XMLHTTTPREQUEST เป็นงานตามสัญญา:
// จากสัญญาของ Jake Archibald และกลับมา: // http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promising-xmlhttprequestfunction get (url) {// กลับสัญญาใหม่ ส่งคืนสัญญาใหม่ (ฟังก์ชั่น (แก้ไข, ปฏิเสธ) {// ทำ XHR stuff ปกติ var req = ใหม่ xmlhtttprequest (); req.open ('get', url); req.onload = function () {// นี้เรียกว่าใน 404 ฯลฯ // } else {// มิฉะนั้นปฏิเสธข้อความสถานะ // ซึ่งหวังว่าจะเป็นข้อผิดพลาดที่มีความหมาย (ข้อผิดพลาด (req.statustext)); {console.log ("ความสำเร็จ!", การตอบสนอง);}, ฟังก์ชั่น (ข้อผิดพลาด) {console.error ("ล้มเหลว!", ข้อผิดพลาด);});Promise.resolve () และ Promise.reject () สามารถเรียกได้โดยตรง บางครั้งเมื่อเราพิจารณาว่าสัญญาไม่จำเป็นต้องดำเนินการเราไม่จำเป็นต้องใช้สิ่งใหม่เพื่อสร้างวัตถุสัญญา แต่สามารถเรียกสัญญาโดยตรง resolve () และ promise.reject () ตัวอย่างเช่น:
var usercache = {}; ฟังก์ชั่น getUserDetail (ชื่อผู้ใช้) {// ในทั้งสองกรณีแคชหรือไม่สัญญาจะถูกส่งคืนถ้า (usercache [ชื่อผู้ใช้]) {// ส่งคืนสัญญาโดยไม่มีคำหลัก "ใหม่" } // ใช้ FETCH API เพื่อรับข้อมูล // FETCH ส่งคืนการส่งคืนสัญญา ('ผู้ใช้/' + ชื่อผู้ใช้ + '.JSON'). จากนั้น (ฟังก์ชั่น (ผลลัพธ์) {USERCACHE [ชื่อผู้ใช้] = ผลลัพธ์กลับ;})เนื่องจากสัญญาจะกลับมาอย่างแน่นอนเราสามารถใช้วิธีการจับและจับเพื่อจัดการค่าคืนได้!
จากนั้นวิธีการ
อินสแตนซ์วัตถุสัญญาทั้งหมดมีวิธีการแล้วซึ่งใช้ในการโต้ตอบกับสัญญานี้ ขั้นแรกวิธีการนั้นจะเรียกฟังก์ชั่นการแก้ไข () โดยค่าเริ่มต้น:
สัญญาใหม่ (ฟังก์ชั่น (แก้ไข, ปฏิเสธ) {// a mock async action โดยใช้ settimeout settimeout (ฟังก์ชัน () {resolve (10);}, 3000);}) จากนั้น (ฟังก์ชั่น (ผลลัพธ์) {console.log (ผลลัพธ์);}); // จากคอนโซล: // 10จากนั้นเวลาทริกเกอร์ของการดำเนินการโทรกลับก็คือการดำเนินการตามสัญญา นอกจากนี้เรายังสามารถดำเนินการโทรกลับในวิธีการดังกล่าวได้:
สัญญาใหม่ (ฟังก์ชั่น (แก้ไข, ปฏิเสธ) {// a mock async การกระทำโดยใช้ settimeout settimeout (function () {resolve (10);}, 3000);}) จากนั้น (ฟังก์ชั่น (num) {console.log ('ก่อนแล้ว:', num); }). จากนั้น (ฟังก์ชั่น (num) {console.log ('สุดท้ายแล้ว:', num);}); // จากคอนโซล: // ก่อนจากนั้น: 10 // วินาทีจากนั้น: 20 // สุดท้าย: 40คุณจะพบว่าการโทรแต่ละครั้งจะใช้ค่าส่งคืนของก่อนหน้านี้จากนั้นโทรเป็นพารามิเตอร์
หากมีการดำเนินการตามสัญญาและเรียกอีกครั้งว่าการดำเนินการโทรกลับจะถูกดำเนินการอีกครั้ง หากฟังก์ชั่นการปฏิเสธการโทรกลับถูกดำเนินการในสัญญานี้และวิธีการดังกล่าวจะถูกเรียกฟังก์ชันการโทรกลับจะไม่ถูกเรียกใช้งาน
วิธีจับ
จับเมื่อสัญญาถูกปฏิเสธ (ปฏิเสธ) วิธีการจับจะถูกดำเนินการ:
สัญญาใหม่ (ฟังก์ชั่น (แก้ไข, ปฏิเสธ) {// a mock async การกระทำโดยใช้ settimeout settimeout (function () {ปฏิเสธ ('เสร็จสิ้น!');}, 3000);}) จากนั้น (ฟังก์ชั่น (e) {console.log ('เสร็จ', e);}) เสร็จแล้ว!'โดยปกติแล้วเราจะจัดการผลลัพธ์ของความล้มเหลวในการดำเนินการในวิธีการปฏิเสธและดำเนินการข้อยกเว้นผลลัพธ์ในการจับ:
ปฏิเสธ (ข้อผิดพลาด ('ไม่พบข้อมูล'));
สัญญาทั้งหมด วิธี
มักจะมีสถานการณ์เมื่อเราเรียกแบบอะซิงโครนัส: เราจำเป็นต้องโทรหาการดำเนินการแบบอะซิงโครนัสหลายครั้งในเวลาเดียวกัน แต่เราหวังว่าเราจะดำเนินการตอบสนองหลังจากการดำเนินการทั้งหมดเสร็จสิ้น - นี่คือบทบาทของสัญญาทั้งหมด วิธีการทั้งหมดสามารถรับสัญญาหลายข้อเป็นพารามิเตอร์ในรูปแบบของอาร์เรย์และฟังก์ชันการโทรกลับจะถูกเรียกหลังจากสัญญาทั้งหมดเหล่านี้ดำเนินการสำเร็จ
Promise.All ([Promise1, Promise2]) จากนั้น (ฟังก์ชั่น (ผลลัพธ์) {// ทั้งสองสัญญาได้รับการแก้ไข}) จับ (ฟังก์ชั่น (ข้อผิดพลาด) {// หนึ่งหรือมากกว่าสัญญาถูกปฏิเสธ});ตัวอย่างที่ดีของการใช้สัญญาทั้งหมดคือการดำเนินการ AJAX หลายรายการ (ผ่านการดึง) การโทร:
var request1 = fetch ('/users.json'); var request2 = fetch ('/articles.json'); Promise.all ([request1, request2]) จากนั้น (ฟังก์ชั่น (ผลลัพธ์) {// ทั้งสองสัญญาทำ!});นอกจากนี้เรายังสามารถทำการรวมกันของการดึงข้อมูลและ API ของแบตเตอรี่เพราะพวกเขาทั้งหมดกลับมาสัญญา:
Promise.All ([fetch ('/users.json'), navigator.getBattery ()]). จากนั้น (ฟังก์ชั่น (ผลลัพธ์) {// ทั้งสองสัญญาทำ!});เมื่อฟังก์ชั่นการปฏิเสธถูกเรียกในสัญญาการดำเนินการจะถูกปฏิเสธและไม่สามารถทำให้เสร็จได้ตามปกติสถานการณ์จะซับซ้อนเล็กน้อย เมื่อสัญญาถูกปฏิเสธวิธีการจับจะจับฟังก์ชั่นปฏิเสธที่ดำเนินการครั้งแรก:
var req1 = สัญญาใหม่ (ฟังก์ชั่น (แก้ไข, ปฏิเสธ) {// การกระทำจำลอง async โดยใช้ settimeout settimeout (ฟังก์ชั่น () {แก้ไข ('แรก!');}, 4000);}); var req2 = สัญญาใหม่ 3000);}); Promise.All ([req1, req2]) จากนั้น (ฟังก์ชั่น (ผลลัพธ์) {console.log ('จากนั้น:', one);}). จับ (ฟังก์ชั่น (err) {console.log ('catch:', err);}); // จากคอนโซล: //สัญญาทั้งหมดเป็นอินเทอร์เฟซที่สำคัญมากและจะมีบทบาทสำคัญใน APIs สัญญาที่เกิดขึ้นใหม่จำนวนมาก
สัญญา. RACE
Promise.race เป็นฟังก์ชั่นที่น่าสนใจ - ไม่รอให้สัญญาทั้งหมดได้รับการแก้ไขหรือปฏิเสธ แต่ในสัญญาทั้งหมดมันจะยิงตราบใดที่การประหารชีวิตครั้งเดียวสิ้นสุดลง:
var req1 = สัญญาใหม่ (ฟังก์ชั่น (แก้ไข, ปฏิเสธ) {// การกระทำแบบจำลอง async โดยใช้ settimeout settimeout (ฟังก์ชั่น () {แก้ไข ('ก่อน!');}, 8000);}); var req2 = สัญญาใหม่ 3000);}); Promise.race ([req1, req2]) จากนั้น (ฟังก์ชั่น (หนึ่ง) {console.log ('จากนั้น:' หนึ่ง);}). จับ (ฟังก์ชั่น (หนึ่ง, สอง) {console.log ('จับ:' หนึ่ง);}); // จากคอนโซล: //สถานการณ์ที่มีประโยชน์คือการดาวน์โหลดทรัพยากรจากเซิร์ฟเวอร์มิเรอร์หลายตัว เมื่อผลตอบแทนหนึ่งผลตอบแทนอื่นจะไม่ถูกประมวลผล
เรียนรู้ที่จะใช้สัญญา
สัญญาเป็นหัวข้อที่น่าสนใจมากในช่วงไม่กี่ปีที่ผ่านมาและมันถูกดึงออกมาจาก JavaScript เพื่อเป็นสถาปัตยกรรมภาษา ฉันเชื่อว่าเราจะเห็น API JavaScript มากขึ้นเรื่อย ๆ ซึ่งจะใช้รูปแบบตามสัญญา
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น