为什么VS代码在Promise中拒绝处理exception?

拿这个代码,我们有一个承诺,调用一个失败的函数,它应该把错误传递给承诺的catch方法。
从terminal上跑时它工作得很好。 但是,当通过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:
版本1.14.2
提交cb82feb
date2017-07-19T23:26:08.116Z
壳牌1.6.6
渲染器56.0.2924.87
节点7.4.0

正如@TJCrowder在评论中指出的那样:

只有在处理程序连接之前引发exception时才会发生这种情况。 例如,这不会导致它,因为当exception转换为拒绝时,已经有一个拒绝处理程序:

 new Promise((resolve, reject) => setTimeout(() => { try { throw new Error(); } catch (e) { reject(e); } }, 0)).catch(error => console.log("Error:", error)); 

原来这是使用vscode来debuggingNodejs的已知“bug”。 就像在这个问题 (在vscode git仓库中)所解释的那样,发生这种情况是因为Nodejs在遇到rejectcallback时发送带有undefinedexception的break事件。 当vscode的debugging器看到这个中断事件时,它会对未知的exception做它应该做的事情,它暂停执行,然后抛出exception。
更进一步,在这个问题上 (在vscode-node-debug2存储库上) @roblourens说:

如果在连接error handling程序之前拒绝承诺,则即使只检查了“未捕获的exception”,debugging程序也将中断。 如果在连接error handling程序后被拒绝,它按预期工作。 而真正的问题是承诺不知道拒绝是否会被处理。

您仍然可以使用vscode来开发基于Promise的系统,但是您需要closuresvscode中的所有error handling,如下所示,确保没有任何选项被打勾。 注意:由于这远远不是最佳的解决scheme,所以将来可能会发生改变或改进。

(我已经评论了vscode的问题,并会更新这个post,如果我学到了有用的东西)

EDIT1:
我发现另一个解决方法是在vscode中定义一个键绑定来运行命令workbench.action.debug.run 。 这将运行当前选定的debugging选项,而无需附加debugging器。 这意味着您可以使debugging器保持正常的设置,而当您需要使用被拒绝的承诺时,使用新的键盘命令运行代码。

 /* keybindings.json */ [ { "key": "ctrl+shift+b", "command": "workbench.action.debug.start" /* Attaches debugger */ }, { "key": "ctrl+b", "command": "workbench.action.debug.run" /* Runs without debugger */ } ] 

EDIT2:
正如@TJCrowder在评论中指出的那样:

只有在处理程序连接之前引发exception时才会发生这种情况。 例如,这不会导致它,因为当exception转换为拒绝时,已经有一个拒绝处理程序:

 new Promise((resolve, reject) => setTimeout(() => { try { throw new Error(); } catch (e) { reject(e); } }, 0)).catch(error => console.log("Error:", error)); 

当然他是对的。 下面的代码在附带debugging器的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 });