Node.js 为什么异常堆栈中的根条目因上下文而异?
据我所知,(未群集的)nodejs程序中的所有代码都在同一个线程中运行。考虑到这一点,我希望所有这些代码都将作为同一根事件循环的子级运行,因此,如果检查堆栈跟踪以查找在不同回调中运行的代码,我们最终仍然会回溯到该事件循环的同一条目(“分派事件”行)。但事实并非如此,我不明白为什么 考虑以下几点:Node.js 为什么异常堆栈中的根条目因上下文而异?,node.js,Node.js,据我所知,(未群集的)nodejs程序中的所有代码都在同一个线程中运行。考虑到这一点,我希望所有这些代码都将作为同一根事件循环的子级运行,因此,如果检查堆栈跟踪以查找在不同回调中运行的代码,我们最终仍然会回溯到该事件循环的同一条目(“分派事件”行)。但事实并非如此,我不明白为什么 考虑以下几点: function printStackTrace() { console.log(new Error().stack); } printStackTrace(); setTimeout(pri
function printStackTrace() {
console.log(new Error().stack);
}
printStackTrace();
setTimeout(printStackTrace, 1000);
运行该程序将产生:
Error
at printStackTrace (/tmp/node/test.js:4:17)
at Object.<anonymous> (/tmp/node/test.js:7:1)
at Module._compile (module.js:446:26)
at Object..js (module.js:464:10)
at Module.load (module.js:353:32)
at Function._load (module.js:311:12)
at Array.0 (module.js:484:10)
at EventEmitter._tickCallback (node.js:190:39)
Error
at Object.printStackTrace [as _onTimeout] (/tmp/node/test.js:4:17)
at Timer.ontimeout (timers.js:94:19)
因此,每个上的根(最底部)项是不同的(分别在EventEmitter、Timer和ReadStream中)。其他回调(如net)也是如此
所以我想
- 事件循环是本机(C++)代码,因此它不会显示在堆栈跟踪中,异步服务的基本提供者(repl.js、timers.js等)使用本机v8 api调用向其注册
- 事件循环是JavaScript,但是
有特殊代码来隐藏它(作为不必要的实现细节)Error()
Error
at null._onTimeout (repl:1:38)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
那么让我们去看电影吧。此行位于listOnTimeout
函数中,该函数被分配给Timer
实例的onttimeout
属性
A使用libuv;它是C++代码,代码< > OnTimeOuts< /Cuff>函数> < /P>
这样,你的答案是:栈的根是由C++代码调用的JavaScript函数(无论是定时器还是流管道)。
Error
提供给您的堆栈跟踪不会显示调用函数所涉及的任何本机代码。事件循环本身是由V8(本机代码)实现的,而不是JavaScript,因此,您不会看到超出该边界的任何内容
所以发生的事情和你的第一个猜测非常接近。JavaScript代码通过为函数设置某些属性(或在调用本机代码时将函数作为参数传递)来注册回调。当C++想要调用该函数时,它得到引用并指示V8通过调用.< /p>调用函数。
如果您对V8的工作方式感兴趣,这是一个很好的开始。您可能希望将此问题的链接发送到freenode IRC上的#node.js频道。
setTimeout(function() { console.log(new Error().stack) }, 1);
Error
at null._onTimeout (repl:1:38)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)