Chrome 自动格式化错误堆栈,这是如何工作的?
Chrome automatically formats Error stacks, how does this work?
(new Error('foo')).stack
的内容看起来像这样:
Error: foo
at Object.notifier (http://localhost:6969/js/main.js:12705:37)
at trackHookChanges (http://localhost:6969/js/main.js:1813:27)
at UseState (http://localhost:6969/js/main.js:1982:13)
at K._.data (http://localhost:6969/js/main.js:70174:6005)
at K (http://localhost:6969/js/main.js:70174:6380)
at Z (http://localhost:6969/js/main.js:70174:9187)
然而,当我console.log
它时,它看起来像:
Error: foo
at Object.notifier (wdyr.ts:10)
at trackHookChanges (whyDidYouRender.js:1306)
at UseState (whyDidYouRender.js:1475)
at K._.data (index.esm.js:1)
at K (index.esm.js:1)
at Z (index.esm.js:1)
Chromedevtools 是否正在使用 sourcemaps 自动更改正在记录的字符串?有没有一种简单的方法可以访问我的代码中的源文件名?我想忽略源自某些 NPM 模块的错误。
不幸的是(但对开发人员来说是幸运的)是的,Chrome使用源映射来格式化控制台中的错误并且(仍然)无法访问相同的功能它使用或输出它产生的。即使有可能,它也只适用于特定的 browser/platform.
TLDR
使用 StackTraceJS 模拟浏览器 sourcemap 分辨率或通过原型或任何属性过滤错误(例如 Error.message
)
讨论
JS 错误堆栈跟踪一团糟,因此不可靠:
- 它们非常依赖 运行ning 环境,如果您 运行 在 Chrome 上编写代码,您最终可能会得到与 运行ning 不同的堆栈它在 Firefox、IE 或节点上(即使在最近的时间里,它们在环境之间达成了 “stacktrace 协议”)。
- 错误堆栈跟踪的最大长度为(几乎总是)10 行,因此如果您的函数(挂钩)在此时间之前被调用,您将永远无法捕捉到它。
- 内部或延迟回调可以 erase/change/augment 在某些环境中函数的堆栈跟踪(可能很难,有时不可能捕获在
setTimeout
中调用的回调的完整堆栈跟踪示例)
部分解决方案(StackTraceJS)
如果你能负担得起对 sourcemap 的 http 请求,你可以利用 Chrome(或任何其他浏览器)用来解析错误堆栈跟踪文件并将其映射到原始文件中的相同机制,并且过滤那些你不喜欢的。这个操作的缺点是你的代码必须用类似 promise 的链完全重写(因为 http 请求)。
幸运的是,已经有一个库可以使这个过程变得容易得多:StackTraceJS,你可以试一试。
这是它的用法(来自图书馆文档):
var error = new Error('BOOM!');
StackTrace.fromError(error).then(callback).catch(errback)
/*
==> Promise([
{functionName: 'fn', fileName: 'file.js', lineNumber: 32, columnNumber: 1},
{functionName: 'fn2', fileName: 'file.js', lineNumber: 543, columnNumber: 32},
{functionName: 'fn3', fileName: 'file.js', lineNumber: 8, columnNumber: 1}
], Error)
*/
旁注
正如您在问题评论中所述,您正在使用 React,并且通常的工作管道是使用 wepack 或其他 js 捆绑器从所有依赖项输出单个 JS 文件。在开发过程中,您从错误堆栈中找出文件可能不会遇到任何问题,但在生产中,您可以从包中省略源映射信息,或者有一些 internal/uglified 文件名未与原始文件链接。这意味着您的代码行为可能会在 dev/prod 配置之间发生变化,具体取决于您的构建管道。
理论解
(proto-OOP)理论指出使用原型来区分错误类型以过滤不需要的行为。
所以首先你应该使用自定义class来定义抛出的错误您的 application/library(参见 Custom Error - MDN 部分)。通过这样做,您 必须 在您的代码中仅抛出或扩展您的 CustomError。
其次,您 应该 通过其 type/properties 而不是其源文件来过滤错误,所以(如果可以的话)检查第 3 方函数可以抛出哪些 class 错误。
通过这种方式,可以很容易地仅隔离那些第 3 方错误,您可以在 try/catch
块内进行简单的继承检查:
try { /* dangerous code */ }
catch (ex) {
if (ex instanceof MyError) { /* handle your errors */ }
else if (ex instanceof The3rdPartyCustomError) { /* handle specific 3rd party CustomError */ }
else if (ex.__proto__ instanceof Error) { /* handle generic 3rd party CustomErrors */ }
else { /* handle native errors (or bad practice 3rd party errors) */ }
}
但是所有这些理论都很难实现,特别是因为 3rd 方库很少实现他们的 CustomError classes,所以你最终将只处理本机错误和你定义的 classes.
试一试,看看什么样的错误会抛出你的第 3 方库。
也许更简单的解决方案是通过 Error.message
或任何其他在您的域案例中可能比预期效果更好的属性来过滤错误。
(new Error('foo')).stack
的内容看起来像这样:
Error: foo
at Object.notifier (http://localhost:6969/js/main.js:12705:37)
at trackHookChanges (http://localhost:6969/js/main.js:1813:27)
at UseState (http://localhost:6969/js/main.js:1982:13)
at K._.data (http://localhost:6969/js/main.js:70174:6005)
at K (http://localhost:6969/js/main.js:70174:6380)
at Z (http://localhost:6969/js/main.js:70174:9187)
然而,当我console.log
它时,它看起来像:
Error: foo
at Object.notifier (wdyr.ts:10)
at trackHookChanges (whyDidYouRender.js:1306)
at UseState (whyDidYouRender.js:1475)
at K._.data (index.esm.js:1)
at K (index.esm.js:1)
at Z (index.esm.js:1)
Chromedevtools 是否正在使用 sourcemaps 自动更改正在记录的字符串?有没有一种简单的方法可以访问我的代码中的源文件名?我想忽略源自某些 NPM 模块的错误。
不幸的是(但对开发人员来说是幸运的)是的,Chrome使用源映射来格式化控制台中的错误并且(仍然)无法访问相同的功能它使用或输出它产生的。即使有可能,它也只适用于特定的 browser/platform.
TLDR
使用 StackTraceJS 模拟浏览器 sourcemap 分辨率或通过原型或任何属性过滤错误(例如 Error.message
)
讨论
JS 错误堆栈跟踪一团糟,因此不可靠:
- 它们非常依赖 运行ning 环境,如果您 运行 在 Chrome 上编写代码,您最终可能会得到与 运行ning 不同的堆栈它在 Firefox、IE 或节点上(即使在最近的时间里,它们在环境之间达成了 “stacktrace 协议”)。
- 错误堆栈跟踪的最大长度为(几乎总是)10 行,因此如果您的函数(挂钩)在此时间之前被调用,您将永远无法捕捉到它。
- 内部或延迟回调可以 erase/change/augment 在某些环境中函数的堆栈跟踪(可能很难,有时不可能捕获在
setTimeout
中调用的回调的完整堆栈跟踪示例)
部分解决方案(StackTraceJS)
如果你能负担得起对 sourcemap 的 http 请求,你可以利用 Chrome(或任何其他浏览器)用来解析错误堆栈跟踪文件并将其映射到原始文件中的相同机制,并且过滤那些你不喜欢的。这个操作的缺点是你的代码必须用类似 promise 的链完全重写(因为 http 请求)。
幸运的是,已经有一个库可以使这个过程变得容易得多:StackTraceJS,你可以试一试。
这是它的用法(来自图书馆文档):
var error = new Error('BOOM!');
StackTrace.fromError(error).then(callback).catch(errback)
/*
==> Promise([
{functionName: 'fn', fileName: 'file.js', lineNumber: 32, columnNumber: 1},
{functionName: 'fn2', fileName: 'file.js', lineNumber: 543, columnNumber: 32},
{functionName: 'fn3', fileName: 'file.js', lineNumber: 8, columnNumber: 1}
], Error)
*/
旁注
正如您在问题评论中所述,您正在使用 React,并且通常的工作管道是使用 wepack 或其他 js 捆绑器从所有依赖项输出单个 JS 文件。在开发过程中,您从错误堆栈中找出文件可能不会遇到任何问题,但在生产中,您可以从包中省略源映射信息,或者有一些 internal/uglified 文件名未与原始文件链接。这意味着您的代码行为可能会在 dev/prod 配置之间发生变化,具体取决于您的构建管道。
理论解
(proto-OOP)理论指出使用原型来区分错误类型以过滤不需要的行为。
所以首先你应该使用自定义class来定义抛出的错误您的 application/library(参见 Custom Error - MDN 部分)。通过这样做,您 必须 在您的代码中仅抛出或扩展您的 CustomError。
其次,您 应该 通过其 type/properties 而不是其源文件来过滤错误,所以(如果可以的话)检查第 3 方函数可以抛出哪些 class 错误。
通过这种方式,可以很容易地仅隔离那些第 3 方错误,您可以在 try/catch
块内进行简单的继承检查:
try { /* dangerous code */ }
catch (ex) {
if (ex instanceof MyError) { /* handle your errors */ }
else if (ex instanceof The3rdPartyCustomError) { /* handle specific 3rd party CustomError */ }
else if (ex.__proto__ instanceof Error) { /* handle generic 3rd party CustomErrors */ }
else { /* handle native errors (or bad practice 3rd party errors) */ }
}
但是所有这些理论都很难实现,特别是因为 3rd 方库很少实现他们的 CustomError classes,所以你最终将只处理本机错误和你定义的 classes.
试一试,看看什么样的错误会抛出你的第 3 方库。
也许更简单的解决方案是通过 Error.message
或任何其他在您的域案例中可能比预期效果更好的属性来过滤错误。