如果我的一个电话中有一个try/catch
,它会导致堆栈重置"重置"在那时候。我有两个问题 -
1)为什么会这样?我想象一下v8引擎是如何工作的,但知道原因会很有趣。
2)有没有一个很好的解决方案来使用async/await
并仍然保持整个堆栈跟踪?现在我在函数调用链中一直放置try/catch
并将错误一直滚动到一个新的错误中(使用VError)。
以下代码给出了我期望的堆栈跟踪
async function one() {
throw new Error("blah");
}
async function two() {
await one();
}
async function three() {
await two();
}
async function four() {
try {
await three();
} catch (e) {
console.log(e);
}
}
four();
堆栈跟踪
Error: blah
at one (/dev/async-stack/correct-stack.js:2:9)
at two (/dev/async-stack/correct-stack.js:6:9)
at three (/dev/async-stack/correct-stack.js:10:9)
at four (/dev/async-stack/correct-stack.js:15:11)
at Object.<anonymous> (/dev/async-stack/correct-stack.js:21:1)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
在中间插入try/catch
会导致堆栈跟踪从最后try/catch
开始。
async function one() {
throw new Error("blah");
}
async function breaker() {
return true;
}
async function stack() {
try {
await breaker();
} catch (error) {
throw error;
}
}
async function two() {
await stack(); // <-- this call
await one();
}
async function three() {
await two();
}
async function four() {
try {
await three();
} catch (e) {
console.log(e);
}
}
four();
堆栈跟踪
Error: blah
at one (/dev/async-stack/broken-stack.js:2:9)
at two (/dev/async-stack/broken-stack.js:19:9)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
at Function.Module.runMain (module.js:695:11)
at startup (bootstrap_node.js:188:16)
at bootstrap_node.js:609:3
答案 0 :(得分:3)
async
/ await
语法是如何解决的。对于您的第一个片段,它就像 1
function one() {
return Promise.reject(new Error("blah"));
}
function two() {
return one().then(() => {});
}
function three() {
return two().then(() => {});
}
function four() {
return three().then(() => {}).catch(e => { console.log(e); });
}
four();
而你的第二个片段就像 1
function one() {
return Promise.reject(new Error("blah"));
}
function breaker() {
return Promise.resolve(true);
}
function stack() {
return breaker().then(() => {}).catch(error => { throw error; });
}
function two() {
return stack().then(() => {
// ^^^^^^^ this anonymous function
return one().then(() => {});
})
}
function three() {
return two().then(() => {});
}
function four() {
return three().then(() => {}).catch(e => { console.log(e); });
}
four();
正如您所看到的,one()
确实是从匿名then
回调内部调用的。它实际上与您的标题建议的try
/ catch
没有任何关系,而是在await
调用之前任何one()
。
1:忽略Promise
构造函数调用之类的细节,这些细节可能在内部使用延迟模式,因此它们不会显示在堆栈跟踪中。
更迂腐的方式是写function() { var _resolve, _reject,
_promise = new Promise((res, rej) => { _resolve = res; _reject = rej; }); try { /* function body */ _resolve(_return_value); } catch(e) { _reject(e); } return _promise; }