最近,我一直在对Node.js的核心进行大量研究,并且对Node平台的内部运作存在一些疑问。据我了解,Node.js的工作方式如下:
Node有一个用Javascript编写的API,它使程序员可以与文件系统和网络之类的东西进行交互。但是,所有这些功能实际上都是由C/C++代码(也是Node的一部分)完成的。这是事情变得有些模糊的地方。因此,Chrome V8引擎的工作就是将javascript向下“编译”(解释?)为机器代码。 V8是用C++编写的,而Javascript语言本身是由ECMA指定的,因此诸如关键字和语言功能之类的内容都由它们定义。这使我想到了最初的几个问题:
但这并不能解释在Node上下文中如何解释Javascript。 Node随附的Chrome V8引擎是与Chrome浏览器上运行的引擎完全相同,还是已对其进行修改以与Node一起使用?
这使我想到了下一个问题。因此,Node具有事件驱动的非阻塞IO。它通过事件循环来实现此目的,尽管它通常被称为“节点事件循环”,但实际上是libuv库的一部分,该库是旨在提供异步IO的C++库。从高层次上讲,事件循环实质上是通过回调来访问的,这是Java的 native 功能,这也是Java被选作Node项目语言的原因之一。下面是事件循环如何工作的说明:
这也可以通过这个整洁的小型站点进行现场演示:http://latentflip.com/loupe/
假设我们的Node应用程序需要调用外部API。所以我们这样写:
request(..., function eyeOfTheTiger() {
console.log("Rising up to the challenge of our rival");
});
我们对
request
的调用被插入调用堆栈,并且我们的回调传递到某处,并保留在那里,直到请求操作完成。完成后,回调将传递到回调队列中。每次清除调用栈时,事件循环都会将回调队列顶部的项目推送到执行该调用栈的调用栈中。此事件循环在单个线程上运行。出现问题的地方是有人编写“阻塞”代码,或者是从未离开调用堆栈并有效地占用线程的代码。如果始终在调用堆栈上执行代码,则事件循环永远不会将项目从回调队列中推送到调用堆栈上,并且它们也永远不会执行,从而冻结了应用程序。这使我想到下一个问题:我发现此图像是该过程的演示:
这就是我不确定Chrome V8引擎和libuv之间如何精确交互的地方。我倾向于相信节点绑定(bind)可以促进这种交互,但是我不确定如何实现。在上图中,似乎NodeJS绑定(bind)仅与V8从Javascript向下编译的机器代码进行交互。如果是这样,那么我对V8引擎如何解释Javascript感到困惑,因为Node Bindings可以区分回调和实际代码以立即执行。
我知道这是一个非常复杂的系列问题,但是我相信这将为试图理解Node.js的人们消除许多困惑,并帮助程序员理解事件驱动的优缺点,更基本的非阻塞IO。
状态更新:刚刚观看了Sencha session (Link here)上的精彩演讲。因此,在此演讲中,演示者提到了V8嵌入指南(Link here),并讨论了如何将C++函数公开给Javascript,反之亦然。本质上,它的工作方式是可以将C++函数公开给V8,并指定它希望这些对象如何公开给Javascript,并且V8解释程序将能够识别您的嵌入式C++函数,并在发现与之匹配的Javascript时执行它们。您指定的。例如,您可以向V8公开用C++实际编写的变量和函数。本质上,这就是Node.js所做的;它能够在Javascript中添加诸如
require
之类的函数,这些函数在被调用时实际上会执行C++代码。这可以稍微清除第1个问题,但是并不能完全显示Node标准库如何与V8结合使用。还不清楚libuv如何与任何这些相互作用。
最佳答案
基本上,您正在寻找的是 V8 Templates 。它将所有C++代码公开为JavaScript函数,您可以从V8虚拟机中调用它。您可以在调用函数或访问特定对象属性时关联C++回调(请阅读 Accessors 和 Interceptors )。
我找到了一篇很好的文章,它解释了所有这一切- How does NodeJS work? 。它还说明了libuv如何与Node协同工作以实现异步性。
希望这可以帮助!
关于javascript - 如何在Node.js中解释和执行异步javascript?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36491385/