关于Node.js你必须要知道的原理性知识
来源:互联网 发布:mac jmeter下载安装 编辑:程序博客网 时间:2024/05/01 08:32
前言
最近学习了Node.js,但是发现关于Node.js的原理性资料比较少。比如说Node.js的non-blocking I/O
,event-driven
,single-thread
的具体机制是什么,single-thread
跟 none-blocking
是不是矛盾,event-loop
具体是什么等等这些问题,网络上能讲到这些并给正确解释的很少。但如果认真点找,还是能够总结出来的,于是就有了这篇文章。
none-blocking
,event-driven
,single-thread
释义
none-blocking
即非阻塞,是指当Node.js处理I/O
耗时操作时,是不会使后续的操作阻塞的。怎么理解呢?比如说下面的伪代码:doSomeOperations(); //做一些普通的非I/O操作。 doHttpRequest(url,callback);//网络请求,url是请求的网址,callback会在请求完在后调用。 doSomeOtherOperations();//做另一些普通的非I/O操作。
其中的
doHttpRequest(callback);
在运行的时候,会去请求url
,如果是阻塞式的话,doSomeOtherOperations();
会在doHttpRequest(url,callback);
请求到网页后才被运行,因为doHttpRequest(url,callback);
阻塞了。而Node.js是none-block
非阻塞式的,也即是说doSomeOtherOperations();
不会等待doHttpRequest(url,callback);
请求到网页后才被运行,而是直接就运行了。event-driven
即事件驱动,是指Node.js程序采用一种event
事件加callback
回调函数来监听事件的方式,程序通过写监听事件比如说myEventEmitter.on("event",callback)
,然后使用myEventEmitter.emit('event');
来触发event
,然后监听事件中的callback
就会运行了。single-thread
即单线程,Node.js采用单线程架构,所以写程序也变得更简单。
none-blocking
VS single-thread
我们知道单线程跟非阻塞是矛盾的,既然单线程
了,又怎么会非阻塞
呢?因为在计算机技术中,处理阻塞以更大地利用计算机资源所采取的方式就是多进程
和多线程
,而现在Node.js这家伙既能做到单线程
又能做到非阻塞
,这难道不让人觉得奇怪吗?
在这里我们需要明确的是,我们在Node.js写的代码是运行在主线程
上面的,而所谓的single-thread
指的也是主线程
的单线程。而实际上,Node.js底层是存在多线程的,Node.js底层采用了libuv
库,libuv
库具有线程池,Node.js的I/O操作会被交给libuv
处理,libuv
通过线程池给I/O操作开新线程。这也是Node.js可以做到none-blocking
的机理。所以要记住的一点是,尽管Node.js是单线程的,但它底层还是大量地使用了多线程,多线程支撑了none-blocking
的特性。
Event loop
我们知道Node.js的事件处理是在event loop
里处理的,但event loop
到底是什么,它的运行流程是怎么样的,相信如果要理解Node.js的运行过程,这些都是绕不开的问题,接下来我们来看一下什么是event loop
。
- 首先我们来看一个图,还有一小段代码。
while(queue.waitForMessage()){ queue.processNextMessage();}
图中Queue
是消息队列(message queue
),而Stack是函数调用的栈(call stack
)。每一个消息(message
)可以理解成一个event
,event
的产生会在message queue
里入队一个message
,每个message
都有对应的callback
(监听该event
的函数)。而上面的代码段就代表了event loop
。
所以结合上面的图片和代码,
event loop
还是比较好理解的。总的运行流程如下:
Node.js在event loop
中,while(queue.waitForMessage()){ queue.processNextMessage();}
不断地检测
message queue
中是否有未被处理的message
,若检测到,则把该message
对应的callback
压入Stack
中,然后执行Stack
中的callback
,每个callback
在执行完毕时会出栈,当Stack
为空时,Node.js又再次检测是否有未处理的message
,如此循环。
process.nextTick(callback)
,setImmediate(callback)
,setTimeout(callback,second)
的区别。
在讲到这三个函数的区别之前,我们先来弄清楚几个概念:tick
,timer
。
tick
我们在写Node.js程序时,会遇到一个函数叫process.nextTick(callback)
, 那么,什么是tick
呢?我们可以把event loop
的每一次循环理解成一个tick
,当调用process.nextTick(callback)
时,会在当前处于处理状态的message
后面新增一个message
,并与函数里的callback
相对应。当前的message
处理完毕后,这个新增的message
就会被处理,callback
也就被调用了。timer
timer
是操作系统的定时器,当使用setTimeout(callback,second)
时,后面的参数second
指定了多久后调用callback
,时间由timer
处理,当指定的时间到时,由操作系统通知Node.js
,然后新增一个相应的message
并入队到message queue
。由于这个通知的过程,相应的任务可能不会马上执行,所以second
的定时是不精准的,只是一个大概值,实际时间会稍大于这个值。
知道了这些概念之后,我们来比较这三个函数的区别:
我们首先来看
setImmediate(callback)
的作用是什么。setImmediate(callback)
并不需要用tick
,timer
来解释,它的行为就是在调用时,在message queue
最末端入队一个新的message
与callback
相对应,当处理完它之前的所有message
后,这个新message
就会被处理了。接下来我们来看
setTimeout(callback,second)
。setTimeout(callback,second)
跟setImmediate(callback)
不同的地方是,setTimeout(callback,second)
在定时时间到才新增一个message
在message queue
的最末端,而setImmediate(callback)
在被调用时就已经新增这样的一个message
了。于是同时调用setImmediate(callback)
和setTimeout(callback,0)
时,前者的callback
总要先运行后者的callback
。- 最后我们来看
process.nextTick(callback)
,我们知道每个event loop
的循环是一个tick
,nextTick
就是指下一个循环就执行,于是就是在当前message
的后面新增一个message
。
因此,如果上面三个函数同时调用,执行先后顺序是process.nextTick(callback)
,setImmediate(callback)
,setTimeout(callback,second)
。
关于异步
我们知道Node.js是异步的,那么,异步指的是什么呢?Node.js中的异步并不仅仅指异步I/O(多线程),前面所说到的process.nextTick(callback)
,setImmediate(callback)
,setTimeout(callback,second)
也是异步机制的一部分,它们把代码的执行延后了。
参考资料:
1.https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
2.http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/
3.https://en.wikipedia.org/wiki/Node.js
4.http://mcgill-csus.github.io/student_projects/Submission2.pdf
- 关于Node.js你必须要知道的原理性知识
- 关于MFi认证你所必须要知道的事情
- 关于MFi认证你所必须要知道的事情
- 关于MFi认证你所必须要知道的事情
- 关于hashCode你必须要知道的三件事
- 关于LLVM,这些东西你必须要知道!
- Java中关于bit操作你必须要知道的事情
- 【两性】你不知道的冷门性知识
- 面试中你必须要知道的语言陷阱
- 面试中你必须要知道的语言陷阱
- 从Idea到付诸实践,你必须要知道的
- 面试中你必须要知道的语言陷阱
- 你必须要知道的20个救命小常识
- 面试中你必须要知道的语言陷阱
- 对于PHP 5.4 你必须要知道的
- 学PHP你必须要知道的几点
- 使用Yeoman你必须要知道的
- 面试中你必须要知道的语言陷阱
- 4.Reverse Words in a String-Leetcode
- 基于OpenCV的人脸识别门禁系统
- fastDFS+nginx配置
- 探究printf
- 三栏布局的实现
- 关于Node.js你必须要知道的原理性知识
- Flume:本地文件到HDFS
- Cordova(Phonegap)在iOS端App的使用(二)---插件的创建
- librbd代码目录解读
- python 类属性
- Leetcode题解 70. Climbing Stairs
- Android Studio 错误 Duplicate files copied in APK META-INF/LICENSE.txt
- 【Leetcode】1.Two Sum 解题
- 【码上杂谈】关于之前对Server上允许的最大TCP连接数理解错误的更正