我正在审查ES6中promises的实现,并且我想知道以下示例中的行为。在这个例子中,我没有立即使用then()方法注册处理程序。这样做(在Chrome 43中)在拒绝承诺时在控制台中记录错误,尽管处理程序仍然执行。
我的假设是我得到错误,因为在我附加处理程序之前拒绝了promise(由于setTimeout)。但按照这种逻辑,当确定要解决承诺时,Chrome是否也应该记录错误?这是怎么回事?
dbgCommand()
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);
答案 0 :(得分:4)
这基本上就是Chrome。在实际的承诺使用中,您几乎从不异步附加拒绝处理程序。拒绝是罕见的(例外情况),你永远不想留下承诺&#34;挂&#34;没有错误处理程序,如果它可能拒绝。
Chrome会告诉您,如果您未同步附加处理程序,则表示您拒绝*。这是为了在以下情况下拒绝网络被拒绝
Promise.resolve().then(function(){
var obj = JSON.prase("{}"); // note the typo
console.log(obj);
});
如果Chrome没有这样做并且这是一个嵌套链 - 您将很难调试错误。 Chrome这样做的事实是一件非常好的事情,它目前正在标准化,因此所有浏览器都会这样做。
故事的寓意是:
很少有理由不这样做。
(*)实际算法在微任务中,但我们忽略它。
如果您有点好奇,请the specification:https://github.com/domenic/unhandled-rejections-browser-spec
以下是Node / io.js的规范:https://gist.github.com/benjamingr/0237932cee84712951a2
答案 1 :(得分:1)
对于可能无法处理错误以便开发人员方便的代码,这只是一个故障保护。它不应该影响其他代码,只能在控制台和调试器中看到。如果在同步代码中引发错误但未捕获,则默认行为是将该错误记录到控制台。使用promises,通过拒绝承诺来捕获和处理抛出的错误。由于JS引擎无法轻易知道将来是否会处理被拒绝的承诺,如果承诺被拒绝,并且在被拒绝时没有处理程序,大多数浏览器都会将消息记录到控制台。 / p>
如果要阻止这种情况,可以使用与同步代码相同的代码。如果您在同步代码中拥有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>
答案 2 :(得分:1)
我建议您重新编写代码以始终如一地使用promises。这是承诺和回调之间的互操作可能导致麻烦的情况之一。承诺意味着链接,如果你发现你有充分的理由在很长一段时间后将它们链接起来,你应该考虑是否可以重新编写代码以同步建立链。
例如,在这种情况下,您需要翻转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.";
}
)