Với một Promise, tại sao các trình duyệt trả lại từ chối hai lần nhưng không giải quyết hai lần?


10

Tôi đang gặp khó khăn khi hiểu javaScript promises. Tôi đã viết đoạn mã sau:

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

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

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

Tôi ngay lập tức thấy điều này trong bảng điều khiển dành cho nhà phát triển Chrome của mình: nhập mô tả hình ảnh ở đây

Nhưng sau khi tôi đợi 5 giây, tin nhắn sẽ tự động chuyển sang màu đen như hình ảnh này: nhập mô tả hình ảnh ở đây

Tôi chưa bao giờ thấy hành vi này trước đây giữa mã javaScript của tôi và bảng điều khiển dành cho nhà phát triển, nơi mã javaScript của tôi có thể "sửa đổi nội dung hiện có" trong bảng điều khiển dành cho nhà phát triển.

Vì vậy, tôi quyết định xem liệu tình huống tương tự có xảy ra với resolveviệc viết mã này không:

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

    resolve("hello world");
});

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

Nhưng trong tình huống này, bảng điều khiển dành cho nhà phát triển của tôi không hiển thị bất cứ điều gì cho đến 5 giây sau, sau đó nó sẽ được in hello world.

Tại sao resolverejectđược đối xử rất khác nhau về thời điểm chúng được viện dẫn?


THÊM

Tôi cũng đã viết mã này:

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);

Điều này gây ra một số kết quả đầu ra cho bảng điều khiển dành cho nhà phát triển. Lỗi đỏ ở thời điểm 0, đỏ chuyển sang đen ở thời điểm 5 giây với văn bản errors hello world, sau đó là thông báo lỗi mới tại thời điểm 6 giây errors 2 hello world, sau đó là thông báo lỗi đỏ ở thời điểm 7 giây. Bây giờ tôi rất bối rối về số lần rejectthực sự được gọi .... Tôi bị mất ...


1
Chỉ là một bên: var p = new Promise(function(resolve,reject){ reject(Error("hello world")); });có thể được viết thành ngữ và chính xác hơn như sau var p = Promise.reject(Error("hello world"));:-)
TJ Crowder

1
Câu hỏi tuyệt vời.
TJ Crowder

Câu trả lời:


11

Wow, thật tuyệt Tôi chưa bao giờ thấy giao diện điều khiển làm điều đó trước đây. (Tuy nhiên, nó có các dạng hành vi động khác, vì vậy ...) Đây là những gì đang diễn ra:

Trong trường hợp đầu tiên, việc thực thi mã của tất cả mọi thứ bên ngoài setTimeoutmã gọi lại của bạn sẽ hoàn tất và ngăn xếp thực thi trả về để chỉ " mã nền tảng " (như thông số Promise / A + gọi nó) đang chạy, không phải mã JavaScript của người dùng (hiện tại). Tại thời điểm đó, lời hứa bị từ chối và không có gì xử lý từ chối, vì vậy đó là một sự từ chối chưa được xử lý và các devtools báo cáo với bạn như vậy.

Sau đó , năm giây sau, cuộc gọi lại của bạn chạy và đính kèm một trình xử lý từ chối. Tại thời điểm này, sự từ chối không còn được xử lý. Rõ ràng, Chrome / V8 / devtools phối hợp với nhau để loại bỏ cảnh báo từ chối chưa được xử lý khỏi bảng điều khiển. Những gì bạn thấy xuất hiện thay vào đó là những gì bạn xuất ra trong trình xử lý từ chối của bạn thông qua console.log. Nếu bạn đính kèm trình xử lý từ chối sớm hơn, bạn sẽ không gặp phải lỗi từ chối chưa được xử lý đó.

Điều này không xảy ra với sự thỏa mãn vì không xử lý sự hoàn thành không phải là một điều kiện lỗi. Không xử lý từ chối là.


1
Ồ điều đó cũng có lý. Tôi nhận thấy FireFox xử lý nó hơi khác nhau. Nhưng ok, có ý nghĩa hơn bây giờ.
Giăng

1
Tôi đã viết giống như vậy trong câu trả lời, nhưng SO đã tải của bạn, vì vậy tôi đã không đăng của tôi. Giải thích tốt đẹp! +1
FZ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.