解决方案
正如 @T.J.Crowder 在 cmets 中指出的那样:
这仅发生在在附加处理程序之前引发异常导致拒绝时。例如,这不会导致它,因为当异常转换为拒绝时,已经附加了一个拒绝处理程序:
new Promise((resolve, reject) => setTimeout(() => {
try {
throw new Error();
} catch (e) {
reject(e);
}
}, 0)).catch(error => console.log("Error:", error));
原来这是使用 vscode 调试 Nodejs 时的一个已知“错误”。
正如this issue(在 vscode git 存储库中)中所解释的那样,发生这种情况是因为 Nodejs 在遇到reject 回调时会发送带有undefined 异常的中断事件。当 vscode 的调试器看到这个中断事件时,它会执行它应该对未知异常执行的操作,它会暂停执行然后抛出异常。
在this issue(在 vscode-node-debug2 存储库中)中的更多信息 @roblourens 说:
如果在附加错误处理程序之前拒绝了一个承诺,即使只检查了“未捕获的异常”,调试器也会中断。如果在附加错误处理程序后它被拒绝,它会按预期工作。
真正的问题是,promise 不知道它的拒绝是否会被处理。
您仍然可以使用 vscode 开发基于 Promise 的系统,但是您需要关闭 vscode 中的所有错误处理,如下所示,确保两个选项均未勾选。
注意:由于这远非最佳解决方案,因此将来可能会进行更改和/或改进。
(我已经在vscode issue 上发表了评论,如果我学到任何有用的信息,我会更新这篇文章)
编辑1:
我发现另一种解决方法是在 vscode 中定义一个键绑定来运行命令workbench.action.debug.run。这将运行当前选定的调试选项,而不附加调试器。这意味着您可以将调试器保持在您的正常设置上,同时在需要处理被拒绝的 Promise 时使用新的键盘命令运行代码。
/* keybindings.json */
[
{
"key": "ctrl+shift+b",
"command": "workbench.action.debug.start"
/* Attaches debugger */
},
{
"key": "ctrl+b",
"command": "workbench.action.debug.run"
/* Runs without debugger */
}
]
编辑2:
正如 @T.J.Crowder 在 cmets 中指出的那样:
这仅发生在在附加处理程序之前引发异常导致拒绝时。例如,这不会导致它,因为当异常转换为拒绝时,已经附加了一个拒绝处理程序:
new Promise((resolve, reject) => setTimeout(() => {
try {
throw new Error();
} catch (e) {
reject(e);
}
}, 0)).catch(error => console.log("Error:", error));
当然他是对的。下面的代码在带有调试器的 vscode 中确实可以工作。
function failingFunc() {
let undef = undefined;
return undef.nope();
}
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
resolve(failingFunc())
} catch (e) {
reject(e);
}
}, 0);
});
promise.then(v => {}).catch((e: Error) => {
console.log(e.message); // Cannot read property 'nope' of undefined
});