搞懂Node的的事件循环
更新时间:2023-12-13Node事件循环简介
Node.js采用事件驱动的异步I/O模型,这个模型是建立在Node事件循环之上的。事件循环是Node运行机制的核心,它负责监听文件的读写、网络请求、定时器等事件,并且维护一个事件队列,将事件交给对应的回调函数来处理。
在Node中事件循环由一个线程负责维护,因此它也被称为单线程模型。不过这个单线程不会成为瓶颈,因为I/O操作大部分时间都是异步发生的,并不会真正阻塞事件循环。
const http = require('http') http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain' }) res.write('Hello World') res.end() }).listen(3000)
事件循环的阶段
Node事件循环分为6个阶段,每个阶段在处理完所有事件后都会触发一个回调函数,然后进入下一个阶段。这些阶段的顺序是固定的,每个阶段的回调函数也是固定的。下面是事件循环的6个阶段:
- timer:执行setTimeout()和setInterval()的回调函数
- pending callbacks:处理系统事件(例如TCP错误类型)和关闭事件,之前未被处理
- idle, prepare:仅在内部使用
- poll:处理I/O事件(例如网络请求、文件读取等等)
- check:执行setImmediate()的回调函数
- close callbacks:执行socket.on('close', ...)的回调函数
setTimeout(() => { console.log('timer phase') }, 0) setImmediate(() => { console.log('check phase') })
事件队列与事件循环顺序
Node事件循环维护一个事件队列,我们可以通过setTimeout()、setInterval()、setImmediate()等函数向该队列中添加事件。事件队列中的事件会按照先进先出的顺序被事件循环监听并处理。
setTimeout(() => { console.log('timer phase 1') }, 0) setTimeout(() => { console.log('timer phase 2') }, 0) setImmediate(() => { console.log('check phase') })
耗时操作对事件循环的影响
耗时操作,例如文件读取、网络请求、数据库查询等等,会阻塞Node执行其他事件的能力。如果这些操作是同步的,它们会针对事件循环造成阻塞。因此,在Node开发中,我们应该尽可能地使用异步操作。
const fs = require('fs') fs.readFile('/path/to/file', (err, data) => { if (err) { throw err } console.log(data) })总结:Node事件循环是一个主要由I/O操作驱动的异步执行机制。它采用单线程模型,将事件委托给对应的回调函数处理,不会因为阻塞I/O操作而造成线程堵塞。Node的事件循环分为6个阶段,每个阶段按照顺序执行,并在处理完所有事件后触发一个回调函数。Node的事件队列维护了所有事件,并以FIFO的方式被事件循环监听和处理。在开发中应该尽可能使用异步操作,避免同步操作阻塞事件循环。