NodeJS

NodeJS 特点

  • 非阻塞式的异步I/O

Node.js中采用了非阻塞型I/O机制,因此在执行了访问文件的代码之后,Nodejs不会阻塞在那里等待文件获取完成,而是把这件事交给底层操作系统,使用回调函数的方式来处理异步的IO,立即转而执行其它的代码,

  • 事件轮询 Nodejs接收到的事件会放到事件队列中,而不是立即执行它,当NodeJS当前代码执行完后他会检查事件队列中是否有事件,如果有,他会取出来依次执行

  • 单线程 Node.js不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的 优点:不会死锁、不用像多线程那样处处在意同步问题、没有线程切换带来的性能上的开销 缺点:多核CPU需单独开子线程、错误会使得整个应用退出、大量计算会占用CPU从而无法调用异步I/O

  • 擅长I/O密集型 主要体现在Node利用事件轮询的方式处理事件,而不是单开一个线程来为每一个请求服务

  • 不擅长CPU密集型业务 由于Node单线程,如果长时间运行计算将导致CPU不能释放,使得后续I/O无法发起。(解决办法是分解大型运算为多个小任务,不阻塞I/O发起) global对象 与在浏览器端不同,浏览器端将希望全局访问的对象挂到window上,而nodejs则将希望全局访问的对象挂到global对象上 CommonJS Buffer、process、console timer定时器相关 setImmediate()、setTimeout(fn, 0) 与 process.nextTick() 两个都是传入一个回调函数,当同步事件执行完之后马上执行。 执行顺序依次是: process.nextTick() 将回调函数加入到 当前执行栈的尾部,任务队列之前 setTimeout(fn, 0) 回调函数加入到 任务队列尾部。即使是0,也会又4ms的延时 setImmediate() 将回调函数插入到任务队列的最末尾,也不会造成阻塞,但不妨碍其他的异步事件 setImmediate(() => { console.log('setImmediate'); })

setTimeout(() => { console.log('setImmediate'); }, 0)

process.nextTick(() => { console.log('next'); }) node Event Loop nodejs的原理 “单线程,异步I/O,事件驱动”

如上图所示:your code 为编辑代码,node.js 核心,Host environment 为宿主环境(提供各种服务,如文件管理,多线程,多进程,IO etc)

1node.js

这里重点介绍,nodejs组成部分:v8 engine, libuv, builtin modules, native modules以及其他辅助服务。

v8 engine:主要有两个作用 1.虚拟机的功能,执行js代码(自己的代码,第三方的代码和native modules的代码)。            
2.提供C++函数接口,为nodejs提供v8初始化,创建context,scope等。

libuv:它是基于事件驱动的异步IO模型库,我们的js代码发出请求,最终由libuv完成,而我们所设置的回调函数则是在libuv触发。

builtin modules:它是由C++代码写成各类模块,包含了crypto,zlib, file stream etc 基础功能。(v8提供了函数接口,libuv提供异步IO模型库,以及一些nodejs函数,为builtin modules提供服务)。

native modules:它是由js写成,提供我们应用程序调用的库,同时这些模块又依赖builtin modules来获取相应的服务支持

简单总结一下:如果把nodejs看做一个黑匣子,起暴露给开发者的接口则是native modules,当我们发起请求时,请求自上而下,穿越native modules,通过builtin modules将请求传送至v8,libuv和其他辅助服务,请求结束,则从下回溯至上,最终调用我们的回调函数。

2your code

当我们执行node xxx.js的时候,node会先做一些v8初试化,libuv启动的工作,然后交由v8来执行native modules以及我们的js代码。