根本问题是计时器回调作为顶级代码运行,检测其中错误的唯一方法是侦听全局错误事件。这是一个使用全局处理程序来检测此类错误的示例,但它存在一些问题,我将在下面的代码中讨论:
"use strict";
let delayTimer; // declare variable
async function badPromise() {
const p = new Promise((res) => {
let delayTimer = setTimeout(() => { // declare variable!!!
console.log('running timeout code...');
if (1 > 0) throw new Error('This is NOT caught!'); // prevents the promise from ever resolving, but may log an error message to the console
res();
}, 1000);
});
return p;
}
(async () => {
let onerror;
let errorArgs = null;
let pError = new Promise( (res, rej)=> {
onerror = (...args) => rej( args); // error handler rejects pError
window.addEventListener("error", onerror);
})
.catch( args => errorArgs = args); // Catch handler resolves with error args
// race between badPromise and global error
await Promise.race( [badPromise(), pError] );
window.removeEventListener("error", onerror); // remove global error handler
console.log("Made it here");
if( errorArgs) {
console.log(" but a global error occurred, arguments array: ", errorArgs);
}
})();
问题
- 编写代码时不关心传递给使用添加的全局错误处理程序的内容
addEventListener
- 如果使用window.onerror = errorHandler
.
- 示例中出现的任何错误事件都可以赢得承诺竞赛
window
。它不必在badPromise()
调用中生成。
- 如果多个调用同时
badPromise
处于活动状态,则捕获全局错误不会告诉您哪个badPromise
调用出错。
因此badPromise
真的很糟糕,需要用小手套处理。如果您严重无法修复它,您可能需要确保您只有一个未完成的调用,并且您没有做任何其他可能同时产生全局错误的操作。在你的情况下这是否可能不是我可以评论的。
选择
更通用的替代方法可能是在调用之前启动一个计时器,badPromise
并使用它来超时返回的 Promise 的挂起状态;
let timer;
let timeAllowed = 5000;
let timedOut = false;
let timeout = new Promise( res => timer = setTimeout(res, timeAllowed))
.then( timedOut = true);
await Promise.race( [badPromise(), timeout])
clearTimer( timer);
console.log( "timed out: %s", timedOut);