为什么VS Code会在Promise中拒绝处理的异常?

时间:2017-07-24 14:02:19

标签: javascript node.js exception promise visual-studio-code

接受这个代码,我们有一个承诺,它会调用一个失败的函数,它应该将错误向前传递给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

1 个答案:

答案 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
});