学node前先要搞清这些概念

437 阅读3分钟

对于node的特点 “单线程,事件驱动,非阻塞I/O” 虽朗朗上口,却又云里雾里的。经过参考总结谈一下一个小白对node特点的理解吧!

1. 单线程

1.1 进程与线程

  1. 进程:操作系统中进程既是资源分配的基本单元,也是动态基本执行单元。
  2. 线程: 一个进程可以包含若干个线程,它们可以利用进程所拥有的资源。是独立运行和独立调度的基本单位。

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 事件循环

事件循环流程:

  1. 图中的栈是程序的执行栈,程序栈从上到下执行
  2. 函数执行过程中遇到异步任务,会将其分配给子线程去执行
  3. 当执行栈为空时,检查是否有执行完成的任务将其放入任务队列
  4. 重复执行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
  1. nextTick放入执行栈底部先执行输出2
  2. setImmediate执行上图check检查 输出1
  3. 调用同一阶段另一个setImmediate 输出3
  4. 执行nextTick输出4

欢迎大家指出问题提出见解!