接受这个代码,我们有一个承诺,它会调用一个失败的函数,它应该将错误向前传递给promise的catch方法。
从终端跑出来时效果很好。
但是当通过vscode运行时,它会在(1)处爆炸。
function failingFunc() {
let undef = undefined;
return undef.nope();
}
let promise = new Promise((resolve, reject) => {
resolve(failingFunc()); // (1) Explodes when run from vscode
});
promise.then(v => {}).catch((e: Error) => {
console.log(e.message); // (2) Prints when run from the terminal
});
为什么会这样?
vscode about page:
版本1.14.2
提交cb82feb
日期2017-07-19T23:26:08.116Z
壳牌1.6.6
渲染器56.0.2924.87
节点7.4.0
答案 0 :(得分:4)
正如 @ T.J.Crowder 在评论中指出:
在附加处理程序之前抛出异常导致拒绝时,会发生 only 。例如,这不会导致它,因为当异常转换为拒绝时,已经附加了拒绝处理程序:
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存储库中)中所解释的那样,这是因为当遇到undefined
回调时,Nodej会发送一个带有reject
异常的break事件。当vscode的调试器看到这个break-event时,它会执行它应该对未知异常执行的操作,它会暂停执行,然后抛出异常。
this issue中的更多内容(在vscode-node-debug2存储库中) @roblourens 表示:
如果在附加错误处理程序之前拒绝了promise,则调试器将会中断,即使只有"未捕获的异常"检查。如果在附加错误处理程序后它被拒绝,它将按预期工作。 问题确实是承诺不知道是否会处理拒绝的方式。
您仍然可以使用vscode开发基于Promise的系统,但是您需要关闭vscode中的所有错误处理,如下所示,确保没有勾选任何选项。 注意:由于这远非最佳解决方案,因此将来可能会发生变化或改进。
(我已对vscode issue发表评论,如果我了解有用的内容,我会更新此帖子
编辑1:
我发现另一种解决方法是在vscode中定义键绑定以运行命令workbench.action.debug.run
。这将运行当前选定的调试选项,而不将调试器附加到它。这意味着您可以将调试器保持在正常设置,同时在需要处理被拒绝的承诺时使用新的key命令运行代码。
/* 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 在评论中指出的那样:
在附加处理程序之前抛出异常导致拒绝时,会发生 only 。例如,这不会导致它,因为当异常转换为拒绝时,已经附加了拒绝处理程序:
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
});