c语言编程笔录

首页 >   > 笔记大全

笔记大全

搞懂Node的的事件循环

更新时间:2023-12-13

Node事件循环简介

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的方式被事件循环监听和处理。在开发中应该尽可能使用异步操作,避免同步操作阻塞事件循环。