异步javascript在Node.js中是如何解释和执行的?

How is asynchronous javascript interpreted and executed in Node.js?

我最近对 ​​Node.js 的核心进行了大量研究,我对 Node 平台的内部工作原理有一些疑问。据我了解,Node.js 是这样工作的:

Node 有一个 API,用 Javascript 编写,它允许程序员与文件系统和网络等事物进行交互。然而,所有这些功能实际上都是由 C/C++ 代码完成的,也是 Node.js 的一部分。这是事情变得有点模糊的地方。因此,Chrome V8 引擎的工作就是将 "compile"(解释?)javascript 转化为机器码。 V8 是用 C++ 写的,Javascript 语言本身是由 ECMA 指定的,所以诸如关键字和语言的特性之类的东西都是由它们定义的。这引出了我的前几个问题:

  1. 节点标准库如何与节点绑定交互,因为节点绑定是用 C++ 编写的?

  2. Chrome V8 引擎如何在 Node 上下文中解释 Javascript?我知道它使用了一种称为 JIT 的技术,在类似的问题中提到过:(https://softwareengineering.stackexchange.com/questions/291230/how-does-chrome-v8-work-and-why-was-javascript-not-jit-compiled-in-the-first-pl) 但这并没有解释 Javascript 在 Node 的上下文中是如何被解释的。 Node 附带的 Chrome V8 引擎是否与 Chrome 浏览器上的 运行 引擎完全相同,或者它是否经过修改以与 Node 一起使用?

这引出了我的下一个问题。因此 Node 具有 event-driven、non-blocking IO。它通过事件循环实现这一点,虽然它通常被称为 "Node Event Loop",但它实际上是 libuv 库的一部分,libuv 库是一个旨在提供异步 IO 的 C++ 库。在高层次上,事件循环本质上是通过回调访问的,这是一个原生的 Javascript 特性,也是 Javascript 被选为 Node 项目语言的原因之一。下面是事件循环如何工作的说明:

这也可以通过这个简洁的小网站进行现场演示:http://latentflip.com/loupe/ 假设我们的 Node 应用程序需要调用外部 API。所以我们这样写:

request(..., function eyeOfTheTiger() {
   console.log("Rising up to the challenge of our rival");
});

我们对 request 的调用被推送到调用堆栈,我们的回调被传递到某个地方,它一直保存到请求操作完成。当它这样做时,回调被传递到回调队列。每次清除调用堆栈时,事件循环都会将回调队列顶部的项目推入调用堆栈,并在那里执行。此事件循环在单个线程上是 运行。出现问题的地方是有人编写 'blocking' 代码,或者永远不会离开调用堆栈并有效占用线程的代码。如果调用堆栈上始终有代码在执行,那么事件循环将永远不会将回调队列中的项目推送到调用堆栈上,它们也永远不会被执行,这实际上会冻结应用程序。这引出了我的下一个问题:

  1. 如果 Javascript 由 Chrome V8 引擎解释,那么 "controls" 将代码推送到回调队列中是什么? Javascript libuv 事件循环如何处理代码?

我发现这张图片是该过程的演示:

这是我不确定 Chrome V8 引擎和 libuv 究竟如何交互的地方。我倾向于相信 Node Bindings 促进了这种互动,但我不太确定如何。在上图中,NodeJS 绑定似乎只与 V8 从 Javascript 编译下来的机器代码进行交互。如果是这样,那么我对 V8 引擎如何以节点绑定可以区分回调和立即执行的实际代码的方式解释 Javascript 感到困惑。

我知道这是一个很深很复杂的系列问题,但我相信这将有助于为试图理解的人澄清很多困惑Node.js,也有助于程序员理解其优点event-driven、non-blocking IO 在更基本层面上的缺点和缺点。

状态更新:刚看了一场来自 Sencha 会议的精彩演讲(Link here). So in this talk, the presenter mentions the V8 embed guide(Link here),讨论了如何向 Javascript 公开 C++ 函数反之亦然。从本质上讲,它的工作原理是 C++ 函数可以暴露给 V8,并指定它希望那些 objects 暴露给 Javascript 的方式,V8 解释器将能够识别您的嵌入式 C++ 函数并执行如果它发现 Javascript 与您指定的内容相匹配。例如,您可以将实际上用 C++ 编写的变量和函数公开给 V8。这基本上就是 Node.js 所做的;它能够将 require 之类的函数添加到 Javascript 中,这些函数在调用时实际执行 C++ 代码。这稍微澄清了问题 1,但它并没有准确说明 Node 标准库如何与 V8 一起工作。目前还不清楚 libuv 如何与这些交互。

基本上你要找的是V8 Templates. It exposes all your C++ code as JavaScript functions that you can call from within the V8 Virtual Machine. You can associate C++ callbacks when functions are invoked or when specific object properties are accessed (Read Accessors and Interceptors).

我找到了一篇很好的文章,解释了所有这些 - How does NodeJS work?。它还解释了 libuv 如何与 Node 结合使用以实现异步性。

希望对您有所帮助!