home

EventLoop事件循环机制

2025年5年13日 · 764

一、浏览器的多线程机制

浏览器为了实现复杂的页面渲染和交互体验,内部实际上运行着多个线程:

  • GUI 渲染线程:负责页面的布局、绘制等(注意:JS 执行时会阻塞 GUI 渲染线程)。

  • JS 引擎线程:执行 JavaScript 代码(始终只有一个,单线程!)。

  • 定时器线程:管理 setTimeout、setInterval 等定时器。

  • 事件监听线程:处理用户交互(点击、输入等)事件。

  • HTTP 网络请求线程:负责异步处理请求数据,最多可同时处理 5~7 个同源请求。

  • ...

尽管浏览器本身是多线程的,JavaScript 代码的执行依然是单线程的。

二、JS 是“单线程”运行的,所以其中大部分代码都是“同步”的(例如:循环...)

  • 所以在 JS 中千万不要写“死循环”、“死递归”...等操作,这些操作会一直占用 JS 引擎线程,导致后续其他的程序都无法执行
  • 但是 JS 中也有部分“异步”操作的代码
    1. [异步微任务]
    • requestAnimationFrame
    • Promise.then/catch/finally
    • async/await
    • queueMicrotask 手动创建一个异步的微任务
    • MutationObserver
    • IntersectionObserver
    • ...
    1. [异步宏任务]
    • setTimeout/setInterval
    • 事件绑定/队列
    • XMLHttpRequest/Fetch
    • MessageChannel
    • ... JS中的异步操作是:借用浏览器的多线程机制,再基于EventLoop事件循环机制,实现的单线程异步效果!!

三、JS执行流程

  • 浏览器加载页面,除了开辟堆栈内存外,还有创建了两个队列
    1. WebAPI:任务监听队列
    2. EventQueue:事件/任务队列

1.首先:当主线程自上而下执行代码过程中,如果遇到“异步”代码把异步任务放到WebAPl中去监听!

  • 浏览器开辟新的线程去监听是否可以执行

  • 不会阻碍主线程的渲染,它会继续向下执行同步的代码

2.其次:当异步任务被监测为可以执行了,也不会立即去执行,而是把其挪至到EventQueue中排队等待执行!

  • 根据微任务还是宏任务,放在不同的队列中

  • 谁先进来排队的,谁在各自队伍的最前面

PS:对于定时器来讲,设定一个等待时间,到时间后并不一定会立即去执行..

3.最后:当“同步代码”(同步宏任务)“执行完毕”,主线程空闲下来,此时会去EventQueue中把正在排队的异步任务,按照顺序取出来执行!

  • 异步的微任务优先级比较高,不论其任务是先放入的,还是后放入的,只要有可执行的异步微任务,永远先执行它!

  • 同样级别的任务,是谁先放入的「谁先到可执行」,谁先执行!

  • 是要把任务拿到栈中执行,而且是交给主线程去执行,所以只要这个拿出来的任务没有执行完,也不会再去拿其他的任务!

上述就是:EventLoop事件循环机制

EventLoop