Nodejs 特点架构以及Event Loop
首先,我们要清楚Nodejs是什么?Nodejs是一个基于 Chrome V8 引擎 的 JavaScript 运行时环境。所以,它是一种“运行环境”,而不是一门新的语言。
其次,Nodejs的特点有哪些?他跟浏览器不同。我们最开始学习js是伴随着HTML/CSS来学习的,所以刚开始是在浏览器这个环境下运行的js。那nodejs的环境又有哪些特点呢?
第一就是单线程(Single Thread),这个其实在node里面有很多线程,那为什么说是单线程,其实是因为只有一个线程是用来处理js的,其他的线程都是用来处理I/O或者其他操作的。这里不要误解。
第二是非阻塞I/O,因为Nodejs的处理机制是伴随着事件循环的,其中异步的代码会在异步队列中去解决,防止超长时间的处理网络请求等问题来影响到主线程的的处理进展。所以是非阻塞I/O。
第三是事件驱动,在Nodejs中,我们会发现所有的操作都是分为两步来处理的就是事件操作+回调函数,这种机制就会在事件执行之后来通过一个回调函数告诉你执行完毕,继续Nodejs中的事件循环。从而保证一个的高性能、非阻塞的系统。
第四是模块系统,在Nodejs中使用 CommonJS (require) 或 ES Module (import) 来组织代码。引用不同的模块,方便我们去操作。
第五是支持跨平台,Nodejs支持macOS、Linux以及Windows。
弄清楚Nodej的特点之后,我们来讨论一下架构和他的Event Loop。
在说明Nodejs架构之前,我们要知道Nodejs的核心库是libuv ,封装了不同操作系统下的异步 I/O 接口(如 Linux 的 epoll,Mac 的 kqueue)。
那来看一下Nodejs的架构:
js的操作代码 (你的业务逻辑:读文件、写接口、开定时器等)
|
Nodejs的API(fs、http、timers 等封装接口)
|
libuv(核心调度器-同步异步等任务执行)
|
操作系统资源调用(读文件、网络请求、定时器、DNS查询)
这上面就是Nodejs的核心架构。在这个过程中,关于libuv核心调度器里面的事件循环处理的机制是我们一会要继续讨论的,也是Nodejs的一个核心重点。
那在Nodejs拿到事件后应该是怎么去执行的呢?我们要清楚,在Nodejs中其实是有一个调用栈的,会把我们的所有任务都通过调用栈来进行一个执行,但是在这个执行过程中,Nodejs还会启用一个异步任务的队列和一个Tick队列。
当我们任务进入到调用栈后,依次来执行进来的任务,当识别到任务是同步任务的时候(如console.log)会直接进行执行。当识别到任务是异步任务(setTimeout、I/O操作、setImmediate)的时候会将任务放在异步任务的队列中。这个时候Nodejs并不会等待异步任务执行完毕之后才继续执行,而是直接继续执行同步任务。然后有一个时间点,就是当异步任务执行完毕,会触发一个回调函数,这也是我们上面所提到的事件驱动,这个时候在这个回调函数对于不同的任务会有一个不同的划分,如setTimeout会添加到一个timers队列中等待执行;I/O操作会添加到poll队列中;setImmediate会添加到check队列中。
Nodejs在发现回调函数进入到上述的三个队列(timers、poll、check)中后,会依次的去执行这些队列里的任务,当执行完毕之后,如果主线程中还有同步任务,会继续顺序执行;否则等待下一个事件触发继续循环。其中,还有nextTick任务和微任务会在事件循环的三个队列任务执行前去执行。可以看下面的图来理解刚刚所涉及到的内容。
以上就是对Nodejs的特点架构和事件循环的讲解。
💬 如果你对 Node.js 的事件循环机制还有疑问,欢迎在评论区留言讨论! 🎁 想看我出一套“Node.js 从入门到实战项目”的文档合集?点个赞支持一下!