对于node的特点 “单线程,事件驱动,非阻塞I/O” 虽朗朗上口,却又云里雾里的。经过参考总结谈一下一个小白对node特点的理解吧!
1. 单线程
1.1 进程与线程
- 进程:操作系统中进程既是资源分配的基本单元,也是动态基本执行单元。
- 线程: 一个进程可以包含若干个线程,它们可以利用进程所拥有的资源。是独立运行和独立调度的基本单位。
1.2 单线程
单线程意味着同一时间只做一件事。JS在浏览器端主要用于与用户互动和操作dom,为了避免复杂性设计为单线程。node中可以开启子线程,web中html5提供webWorker标准。
node这里的单线程指的是只有一个主线程。1.3 优缺点
优点:可以避免系统分配多线程以及线程间通信时的开销,可以更高效的利用cpu,降低内存的耗用。
缺点:一旦出现错误会导致整个程序崩溃,不擅长大量的计算,无法利用多核cpu。2. 阻塞\非阻塞
2.1 阻塞非阻塞是基于程序调用者角度的概念。
2.2 阻塞、非阻塞
例子:当我们调用fs.readFile()时:
阻塞:程序阻塞待读取文件成功后继续向下执行。 非阻塞:程序继续执行,待文件读取成功后通过回调拿到文件内容。3. 同步\异步
3.1 同步异步是基于被调用者角度的概念。
3.2 同步、异步
例子:读取文件时
同步:fs.readFile()立即根据路径查找读取文件。 异步:被调用者将任务存起来,不立即执行任务。4. 事件驱动
4.1 事件驱动
当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户。webserver一直接受请求而不等待任何读写操作。
4.2 事件循环
事件循环流程:- 图中的栈是程序的执行栈,程序栈从上到下执行
- 函数执行过程中遇到异步任务,会将其分配给子线程去执行
- 当执行栈为空时,检查是否有执行完成的任务将其放入任务队列
- 重复执行2,3步
4.2.1 常见宏任务
setTimeout、setInterval、fs.readFile
4.2.2 常见微任务
nextick、promise.then
4.3 在libuv内部有这样一个事件环机制。在node启动时会初始化事件环
这里每一个阶段都对应一个事件队列,当event loop执行到某个阶段时会将当前阶段对应的队列依次执行。当队列执行完毕或者执行的数量超过上线时,会转入下一个阶段。setImmediate(function(){ console.log(1); process.nextTick(function(){ console.log(4); })})process.nextTick(function(){ console.log(2); setImmediate(function(){ console.log(3); })})//2 1 3 4复制代码
- nextTick放入执行栈底部先执行输出2
- setImmediate执行上图check检查 输出1
- 调用同一阶段另一个setImmediate 输出3
- 执行nextTick输出4
欢迎大家指出问题提出见解!