console.log内错误抛出顺序异常?自定义Error技术问询
首先咱们先拆解你自定义错误实现里的几个关键问题,这些问题直接导致了错误栈或者输出表现不符合预期:
1. 自定义错误的constructor未正确重置
你用CustomError.prototype = Object.create(Error.prototype)实现了继承,但没有把CustomError.prototype.constructor指向自身。这会导致错误对象的构造函数标识混乱,不仅影响instanceof的准确性,还可能让日志输出里的错误类型显示异常。
2. 错误栈(stack)的生成时机错了
你在CustomError构造函数里直接赋值this.stack = (new Error()).stack,这个栈是构造函数内部创建匿名Error时的调用栈,而不是throw语句执行时的栈。比如当你在foo()里抛出CustomError时,栈的顶部会显示CustomError构造函数,而不是foo(),这就造成了错误栈顺序“错位”的错觉。
解决办法
修正自定义错误的实现
我们用更标准的方式实现自定义错误,同时利用Error.captureStackTrace(Node.js和现代浏览器都支持)生成正确的栈追踪:
function CustomError(message) { // 先调用Error构造函数初始化基础属性 const baseError = new Error(message); // 捕获栈追踪,第二个参数排除构造函数本身,让栈从调用它的地方开始 Error.captureStackTrace(this, CustomError); this.name = 'CustomError'; this.message = message; // 兼容旧环境可以直接复用baseError的栈 this.stack = baseError.stack; } // 正确设置原型继承 CustomError.prototype = Object.create(Error.prototype); // 重置constructor指向自身 CustomError.prototype.constructor = CustomError;
如果你的环境支持ES6,用class写法会更简洁直观:
class CustomError extends Error { constructor(message) { super(message); this.name = 'CustomError'; // 手动捕获栈,确保栈从抛出位置开始 Error.captureStackTrace(this, this.constructor); } }
验证效果
用修正后的代码运行你的逻辑:
function foo() { throw new CustomError('custom error message'); } try { foo(); } catch (err) { console.log(err); }
此时console.log输出的错误栈会正确显示错误是从foo()函数抛出的,顺序完全符合预期。
另外,如果是错误信息和其他日志的输出顺序混乱(比如错误日志跑到普通日志后面),那是因为部分环境会异步格式化错误对象。这时候可以把错误转为字符串输出,比如console.log(err.stack),就能保证顺序正确了。
内容的提问来源于stack exchange,提问作者Matus Dubrava

