[英]Do native promises in JavaScript (ES6) have a default onFulfilled handler?
我正在審查ES6中Promise的實現,並在下面的示例中想知道行為。 在此示例中,我沒有立即向then()方法注冊處理程序。 這樣做(在Chrome 43中)會在拒絕諾言的情況下在控制台中記錄一個錯誤,盡管該處理程序仍會執行。
我的假設是我得到錯誤,因為在附加處理程序之前,由於promise被拒絕(由於setTimeout)。 但是按照這種邏輯,當確定要解決承諾時,Chrome瀏覽器是否也不應記錄錯誤? 這里發生了什么?
var par = document.querySelector('p'); var P = new Promise(function(resolve, reject){ var v = Math.random(); if(v < 0.5){resolve(v)} else{reject(v)} }); //wait to attach handlers setTimeout(function(){ var n = P.then( function(v){ par.innerHTML = "Good, "+v+" is less than 0.5."; }, function(v){ par.innerHTML = "Uh oh, "+v+" is greater than or equal to 0.5."; } ) },1000);
<p></p>
基本上這是Chrome的后盾。 在實際的Promise用法中,您幾乎永遠不會異步附加拒絕處理程序。 拒絕是很少見的(像異常一樣),並且如果它可能會拒絕,則您永遠都不想在沒有錯誤處理程序的情況下留下承諾“掛起”。
Chrome讓您知道您拒絕了未附加用於同步*的處理程序。 這是為了在以下情況下吞噬拒收物:
Promise.resolve().then(function(){
var obj = JSON.prase("{}"); // note the typo
console.log(obj);
});
如果Chrome瀏覽器沒有執行此操作,而這是一個嵌套的鏈-您將很難調試錯誤。 Chrome確實可以做到這一點,而且目前已被標准化,因此所有瀏覽器都可以做到這一點。
這個故事的寓意是:
很少有理由不這樣做。
(*)實際的算法在微任務中,但是我們忽略它。
如果您好奇的話,這里是規格 : https : //github.com/domenic/unhandled-rejections-browser-spec
這是Node / io.js的規范: https ://gist.github.com/benjamingr/0237932cee84712951a2
對於可能無法為開發人員提供便利的錯誤而處理的代碼,這只是故障保護。 它不應影響其他代碼,並且僅在控制台和調試器中可見。 如果在同步代碼中引發了錯誤但未捕獲到錯誤,則默認行為是將該錯誤記錄到控制台。 有了諾言,就可以通過拒絕諾言來捕獲和處理拋出的錯誤。 由於JS引擎無法輕易知道將來是否會處理被拒絕的承諾,因此,如果一個承諾被拒絕,並且被拒絕時沒有處理程序,那么大多數瀏覽器會將消息記錄到控制台。
如果要防止這種情況,可以執行與同步代碼類似的代碼。 在同步代碼中有try
/ catch
,可以使用no-op .catch()
處理函數來實現諾言。
var par = document.querySelector('p'); var P = new Promise(function(resolve, reject){ var v = Math.random(); if(v < 0.5){resolve(v)} else{reject(v)} }); P.catch(function(reason){ // noop }); //wait to attach handlers setTimeout(function(){ var n = P.then( function(v){ par.innerHTML = "Good, "+v+" is less than 0.5."; }, function(v){ par.innerHTML = "Uh oh, "+v+" is greater than or equal to 0.5."; } ) },1000);
<p></p>
我建議您對您的代碼進行重做以一致地使用Promise。 這是promise和回調之間的互操作可能引起麻煩的情況之一。 承諾是要鏈接的,如果您發現在很長一段時間后有充分的理由將它們鏈接起來,則應考慮是否可以重新編寫代碼以同步建立鏈接。
例如,在這種情況下,您需要翻轉setTimeout
:
function delay(ms){
return new Promise(function(resolve, reject){
setTimeout(resolve, ms);
});
}
var par = document.querySelector('p');
var P = new Promise(function(resolve, reject){
var v = Math.random();
if(v < 0.5){resolve(v)}
else{reject(v)}
});
P.then(
function(result){
return delay(1000).then(function(){ return result; });
},
function(err){
return delay(1000).then(function(){ throw err; });
}
).then(
function(v){
par.innerHTML = "Good, "+v+" is less than 0.5.";
},
function(v){
par.innerHTML = "Uh oh, "+v+" is greater than or equal to 0.5.";
}
)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.