Node.js 为什么异常堆栈中的根条目因上下文而异?

Node.js 为什么异常堆栈中的根条目因上下文而异?,node.js,Node.js,据我所知,(未群集的)nodejs程序中的所有代码都在同一个线程中运行。考虑到这一点,我希望所有这些代码都将作为同一根事件循环的子级运行,因此,如果检查堆栈跟踪以查找在不同回调中运行的代码,我们最终仍然会回溯到该事件循环的同一条目(“分派事件”行)。但事实并非如此,我不明白为什么 考虑以下几点: function printStackTrace() { console.log(new Error().stack); } printStackTrace(); setTimeout(pri

据我所知,(未群集的)nodejs程序中的所有代码都在同一个线程中运行。考虑到这一点,我希望所有这些代码都将作为同一根事件循环的子级运行,因此,如果检查堆栈跟踪以查找在不同回调中运行的代码,我们最终仍然会回溯到该事件循环的同一条目(“分派事件”行)。但事实并非如此,我不明白为什么

考虑以下几点:

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()
    有特殊代码来隐藏它(作为不必要的实现细节)
以下哪种情况(如果有)是这种情况,通常在nodejs(编辑:或v8)源代码中哪里可以读取真实根事件循环的实现?

答案(或至少是一条线索)就在堆栈跟踪中。只需按照堆栈底部文件中的代码进行操作

我不确定您使用的节点的确切版本(0.6?需要更新!),但在最新版本(0.10.17)中

打印出:

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)