首页 > 语言 > JavaScript > 正文

JavaScript错误处理和堆栈追踪详解

2024-05-06 15:18:24
字体:
来源:转载
供稿:网友

有时我们会忽略错误处理和堆栈追踪的一些细节, 但是这些细节对于写与测试或错误处理相关的库来说是非常有用的. 例如这周, 对于 Chai 就有一个非常棒的PR, 该PR极大地改善了我们处理堆栈的方式, 当用户的断言失败的时候, 我们会给予更多的提示信息(帮助用户进行定位).

合理地处理堆栈信息能使你清除无用的数据, 而只专注于有用的数据. 同时, 当更好地理解 Errors 对象及其相关属性之后, 能有助于你更充分地利用 Errors.

(函数的)调用栈是怎么工作的

在谈论错误之前, 先要了解下(函数的)调用栈的原理:

当有一个函数被调用的时候, 它就被压入到堆栈的顶部, 该函数运行完成之后, 又会从堆栈的顶部被移除.

堆栈的数据结构就是后进先出, 以 LIFO (last in, first out) 著称.

例如:

function c() {  console.log('c');} function b() {  console.log('b');  c();} function a() {  console.log('a');  b();} a();

在上述的示例中, 当函数 a 运行时, 其会被添加到堆栈的顶部. 然后, 当函数 b 在函数 a 的内部被调用时, 函数 b 会被压入到堆栈的顶部. 当函数 c 在函数 b 的内部被调用时也会被压入到堆栈的顶部.

当函数 c 运行时, 堆栈中就包含了 a, b 和 c(按此顺序).

当函数 c 运行完毕之后, 就会从堆栈的顶部被移除, 然后函数调用的控制流就回到函数 b. 函数 b 运行完之后, 也会从堆栈的顶部被移除, 然后函数调用的控制流就回到函数 a. 最后, 函数 a 运行完成之后也会从堆栈的顶部被移除.

为了更好地在demo中演示堆栈的行为, 可以使用 console.trace() 在控制台输出当前的堆栈数据. 同时, 你要以从上至下的顺序阅读输出的堆栈数据.

function c() {  console.log('c');  console.trace();} function b() {  console.log('b');  c();} function a() {  console.log('a');  b();} a();

在 Node 的 REPL 模式中运行上述代码会得到如下输出:

Trace  at c (repl:3:9)  at b (repl:3:1)  at a (repl:3:1)  at repl:1:1 // <-- For now feel free to ignore anything below this point, these are Node's internals  at realRunInThisContextScript (vm.js:22:35)  at sigintHandlersWrap (vm.js:98:12)  at ContextifyScript.Script.runInThisContext (vm.js:24:12)  at REPLServer.defaultEval (repl.js:313:29)  at bound (domain.js:280:14)  at REPLServer.runBound [as eval] (domain.js:293:12)

正如所看到的, 当从函数 c 中输出时, 堆栈中包含了函数 a, b 以及c.

如果在函数 c 运行完成之后, 在函数 b 中输出当前的堆栈数据, 就会看到函数 c 已经从堆栈的顶部被移除, 此时堆栈中仅包括函数 a 和 b.

function c() {  console.log('c');} function b() {  console.log('b');  c();  console.trace();} function a() {  console.log('a');  b();}            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选