ด้วยสัญญาทำไมเบราว์เซอร์กลับปฏิเสธสองครั้ง แต่ไม่ได้รับการแก้ไขสองครั้ง?


10

ฉันมีปัญหาในการทำความเข้าใจ promisesjavaScript ฉันเขียนรหัสต่อไปนี้:

var p = new Promise(function(resolve,reject){

    reject(Error("hello world"));
});

setTimeout(()=>p.catch(e=>console.log(e)),5000);

ฉันเห็นสิ่งนี้ในคอนโซลนักพัฒนาซอฟต์แวร์ Chrome ทันที: ป้อนคำอธิบายรูปภาพที่นี่

แต่หลังจากฉันรอ 5 วินาทีข้อความจะเปลี่ยนเป็นสีดำเหมือนภาพนี้โดยอัตโนมัติ: ป้อนคำอธิบายรูปภาพที่นี่

ฉันไม่เคยเห็นพฤติกรรมนี้มาก่อนระหว่างรหัส javaScript ของฉันและคอนโซลนักพัฒนาซอฟต์แวร์ซึ่งรหัส javaScript ของฉันสามารถ "แก้ไขเนื้อหาที่มีอยู่" ในคอนโซลนักพัฒนาซอฟต์แวร์

ดังนั้นฉันตัดสินใจที่จะดูว่าสถานการณ์เดียวกันเกิดขึ้นกับresolveการเขียนรหัสนี้:

var p = new Promise(function(resolve,reject){

    resolve("hello world");
});

setTimeout(()=>p.then(e=>console.log(e)),5000);

แต่ในสถานการณ์นี้คอนโซลนักพัฒนาซอฟต์แวร์ของฉันจะไม่แสดงผลใด ๆ จนกว่าจะถึง 5 วินาทีหลังจากนั้นซึ่งจะพิมพ์hello worldออกมา

ทำไมresolveและrejectได้รับการปฏิบัติที่แตกต่างกันในแง่ของเมื่อพวกเขาถูกเรียก?


EXTRA

ฉันยังเขียนรหัสนี้:

var p = new Promise(function(resolve,reject){

    reject(Error("hello world"));
});

setTimeout(()=>p.catch(e=>console.log("errors",e)),5000);
setTimeout(()=>p.catch(e=>console.log("errors 2",e)),6000);
setTimeout(()=>p.catch(null),7000);

ซึ่งทำให้หลายเอาต์พุตไปยังคอนโซลผู้พัฒนา ข้อผิดพลาดสีแดง ณ เวลา 0 สีแดงเปลี่ยนเป็นสีดำในเวลา 5 วินาทีด้วยข้อความerrors hello worldจากนั้นข้อความแสดงข้อผิดพลาดใหม่ในเวลา 6 วินาทีerrors 2 hello worldจากนั้นข้อความแสดงข้อผิดพลาดสีแดงในเวลา 7 วินาที ตอนนี้ฉันสับสนมากถึงจำนวนครั้งที่rejectถูกเรียกจริง .... ฉันหลงทาง ...


1
เพียงแค่กัน: var p = new Promise(function(resolve,reject){ reject(Error("hello world")); });สามารถเขียนโดยใช้สำนวนและรัดกุมมากขึ้นเป็นvar p = Promise.reject(Error("hello world"));:-)
TJ Crowder

1
คำถามที่น่ากลัว
TJ Crowder

คำตอบ:


11

ว้าวมันเจ๋งจริงๆ ฉันไม่เคยเห็นคอนโซลทำเช่นนั้นมาก่อน (มันมีพฤติกรรมแบบไดนามิกรูปแบบอื่น ๆดังนั้น ... ) นี่คือสิ่งที่เกิดขึ้น:

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

จากนั้นห้าวินาทีในภายหลังการโทรกลับของคุณจะทำงานและแนบตัวจัดการการปฏิเสธ ณ จุดนี้การปฏิเสธไม่ได้รับการจัดการอีกต่อไป เห็นได้ชัดว่า Chrome / V8 / devtools ทำงานร่วมกันเพื่อลบคำเตือนการปฏิเสธที่ไม่ได้จัดการออกจากคอนโซล console.logสิ่งที่คุณเห็นปรากฏแทนคือสิ่งที่คุณส่งออกในการจัดการปฏิเสธของคุณผ่านทาง หากคุณแนบตัวจัดการการปฏิเสธในไม่ช้าคุณจะไม่ได้รับข้อผิดพลาดการปฏิเสธที่ไม่จัดการ

สิ่งนี้ไม่ได้เกิดขึ้นกับการเติมเต็มเพราะการไม่เติมเต็มการจัดการไม่ใช่เงื่อนไขข้อผิดพลาด ไม่จัดการการปฏิเสธคือ


1
โอ้นั่นทำให้รู้สึก ฉันสังเกตเห็นว่า FireFox จัดการมันแตกต่างกันเล็กน้อย แต่ตกลงตอนนี้เหมาะสมมากขึ้น
จอห์น

1
ฉันเขียนเหมือนเดิมในคำตอบ แต่ดังนั้นคุณโหลดดังนั้นฉันไม่ได้โพสต์ของฉัน คำอธิบายที่ดี! +1
FZ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.