基本理解
-
nodejs不是语言、框架,它是javascript的运行环境,并一定程度上扩展了js的语言功能,比如可以操作文件系统的
fs模块等,可以简单类比为java的jre。 -
nodejs的特点是单线程、异步、非阻塞以及事件驱动。
单线程,并不是指nodejs只有一个线程,nodejs有2类线程,
main线程(也叫event loop线程)和work线程(线程池),单线程是指运行js代码的只有一个线程,原因也很简单,运行js的部分是由V8实现。 -
event loop,实际是一个listener,它和js运行在同一个线程,也就是都在主线程中(所以为什么强调不要阻塞event loop)。 -
运行过程的理解:
⇒ 执行同步代码
⇒ 中间如果遇到异步代码,比如
setTimeout、fs.readfile等等,会交给对应的线程去处理,比如fs就会交给work thread线程池处理,处理完成后把回调推入对应的callback队列。在执行这部分内容的同时,也会触发event loop(指event loop监听器需要被执行,不是立即就执行)。⇒ 同步代码执行完成
⇒ 检查是否有触发
event loop,有的话,执行这个监听器,event loop会去检查6个callback queue,执行队列中的callback。nodejs会使用合适的机制来执行event loop监听器(就是在合适的时机在线程栈中执行这个listener)。 -
http.creatServer(callback()).listen(3000)的理解首先这并不会阻塞线程,不是
while(true)(tomcat就是这样,阻塞线程,监听到后开一个新线程去执行响应),这更像是addEventListener(),当在3000端口监听到请求后,回调会被推入回调队列(也就是poll队列),等待执行。 -
事件驱动
上面的
http例子也是事件驱动的体现,注册监听,事件触发,将回调推入回调队列,等待event loop来检查执行。(这也能解释为什么nodejs作为服务端,可以进行大量的并发了,因为回调都在队列中,没有阻塞主线程,但是记住回调最终也要在主线程中执行,所以回调中也不要有大量的同步计算,否则也会阻塞。) -
对于
setTimeout,I/O,事件注册(onClick)等的理解:实际上抛开固有印象,执行这些方法时,可以简单的看作同步调用了一个API,这个API的作用可能就是调用其他线程去处理了(或者直接理解为API去处理了),然后接着执行后续内容,所以主线程上其实都是**“同步“**的,API执行完后(如果是事件监听,就是监听到事件后),将回调推入回调队列,等待
event loop来执行。 -
nodejs作为服务端,适合I/O密集型应用(可以充分利用工作线程),不适合CPU密集型(都是同步计算,都在主线程(单线程)中执行,容易阻塞)。