实现此目的的一个 hacky 方法是使用调试上下文:
const vm = require('vm');
const Debug = vm.runInDebugContext('Debug'); // Obtain Debug object
Debug.setListener((type, _, e) => { // listen for all debug events
if (type == Debug.DebugEvent.Exception) {
console.log(e.exception().stack) // e is an event object
}
});
Debug.setBreakOnException(); // this is required for Exception event to fire
try {
throw new Error('bla');
} catch(e) {
// ha
}
警告:不要将此代码留在生产环境中,仅用于调试。
显然,它不会调用异步错误,因为它们实际上并没有被抛出,它们只是被创建以传递给回调。
另一种方法是替换可能的错误构造函数:
const OldError = Error;
const MyError = function(message) {
const err = new OldError(message);
OldError.captureStackTrace(err, MyError); // remove top frame from stack trace
console.log(err.stack);
return err;
}
MyError.prototype = Error.prototype; // Fix instanceof
global.Error = MyError;
try {
throw new Error('bla');
} catch(e) {
}
new Error('blabla');
这样你也可以处理异步错误,但不会看到除了实例Error之外的东西是否被抛出。
如果你只对 Promise 感兴趣并且你正在使用原生 v8 Promise,那么你可以试试这个:
const vm = require('vm');
const Debug = vm.runInDebugContext('Debug');
Debug.setListener((type, _, e) => {
if (type == Debug.DebugEvent.PromiseEvent) {
if (e.status() === -1) { // 0=pending, 1=resolved, -1=rejected
console.log(e.value().value().stack);
}
}
});
Promise.reject(new Error('test'))
.catch(() => {});
它可能会产生一些重复,因为它会捕获子承诺拒绝以及原始承诺拒绝。