![](https://i-blog.csdnimg.cn/blog_migrate/dabab071f5537e7940deff35c380ed64.png)
![](https://i-blog.csdnimg.cn/blog_migrate/abc696db2671e2300d4bca9409a97190.png)
这次读了一些关于底层实现的东西:
- 《深浅》第3章 异步I/O - node.js是如何实现异步i/o的
- Udemy 《Learn and Understand NodeJS Learn and Understand NodeJS》 Section 2&3
V8引擎
首先,学习node.js一定要了解V8引擎,他是一个可以把js直接编译成(处理器可以识别的)机器码的东西。
再详细点,V8是一个
- 开源的
- 用C++写的
- 根据ECMA标准实现JavaScript
- 可以把JavaScript编译成处理器可以识别的机器码
- 可以独立运行
- 也可以嵌入其他C++应用
的JavaScript引擎。
Node.js与V8引擎
普通青年使用V8:运行V8, JavaScript -> V8 —compile—> Machine Code
文艺青年则有这样一个大胆的想法:
那些普通的js方法太没意思了,能力优先。如果我可以写一些C++代码,当做Add-on加到V8上,这样V8就有能力识别具有更多的Javascript命令了,就更强大了。比如说file相关的东西,本来js不能做,现在我用c++在底部实现好,然后告诉V8,当用户在js中写道file.open(xxx)的时候,就来用c++执行file open的功能,这样你的js(二b)就是有处理文件能力的js(牛b)了。
文艺青年的想法其实就是我们的Node.js:一个把V8引擎嵌进去的C++应用,这个C++应用实现了超级多的customized新功能,这些功能使得这个应用(Node.js)非常的适合服务器开发。
服务器开发都需要什么新功能呢 === Node.js实现的新功能都包括哪些方面呢:
- 管理可复用代码
- 处理文件
- 处理数据库
- 互联网通信
- 接受request,发送respond
- 处理需要一定时间才能完成的工作
Node.js架构
- 第一层是C++ core,就是那些新加的customized功能 (其他讲解中,还会提到比如event loop,libuv等,这些之后说)。
- 第二层是JS core,这一层用js实现,基于/调用C++ core,让用户可以更好的使用那些C++功能,同时也实现了许多常用的功能。
在node.js源码中,C++ core是在src文件夹内。JS core是在lib文件夹内。由此可见二者的层级关系。
Node.js 异步I/O
Node.js如何实现异步 I/O, 从JS到OS到底发生了哪些步骤(这个是udemy+《深浅》的合体版总结)
- 你写的js代码调用了node.js的JS core (比如 fs相关功能:github.com/nodejs/node…),并且你设定了一个回调函数
- JS core部分调用了C++ core (fs.js 调用的其中一个.cc: github.com/nodejs/node…)
- C++ core调用libuv
- C++ core调用libuv的方法来封装请求对象(异步I/O过程中重要的中间产物,中间指的是从js到os之间),其中包含了异步I/O中最重要的东西之一:回调函数。
- libuv把封装好的请求对象发到OS
- 发到OS中的线程池(thread pool)等待被执行
- 线程池中某一线程将发来的请求对象中包含的I/O操作进行执行,结果存在该请求对象的req->result属性中。然后提交完成状态,也就是类似通知说"我完成了!”,之后把线程归还给线程池
- 处于完成状态的请求对象,被观察者(图中的两个小人儿,不同类型的事件有不同的观察者)在事件循环(Event Loop:大while循环,每个循环叫一个tick)中提出来(通过libuv中方法来检查是否有执行完的请求),然后放到队列(Completed Events Queue)中
- 事件循环从观察者的队列中取出处于完成状态请求对象
- 取出其中包含的I/O操作执行结果以及回调函数,发到V8中执行。到这就达到了调用#1中设定的回调函数的目的。
注:
a. V8引擎执行的JavaScript是同步的(sync)(
stackoverflow.com/questions/2…)且单线程
b. #1-#9 与 #10 是同时在工作的,I/O事件一个一个执行,然后最后发送到V8引擎中一个一个(因为JS是同步的)的执行回调函数
c. 由于b,整个Node.js有了异步I/O的能力
d. 事件驱动(event driven)、非阻塞(non-blocking)I/O的特点也就可以解释了。事件驱动就是指的#7-#10,事件被完成触发了之后各个步骤,直到最后执行回调函数。非阻塞I/O就是整个#1-#10这个过程,我们在V8中执行的JavaScript代码并不会因为事件的执行而停止,#1-#9和#10同时工作,一个执行I/O事件,一个得到通知执行回调函数。
e. 从d的解释中,可以更好的理解上一篇文章中最后那段说Node.js是单线程/多线程。
下次写事件(Event)和事件发射器(Event Emitter)相关的东西。欢迎大家交流,指正~
作者:macctown
链接:https://juejin.im/post/5a24cfe7f265da431e16977a
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。