EventLoop事件循环机制
2025年5年13日 · 764 字
一、浏览器的多线程机制
浏览器为了实现复杂的页面渲染和交互体验,内部实际上运行着多个线程:
-
GUI 渲染线程:负责页面的布局、绘制等(注意:JS 执行时会阻塞 GUI 渲染线程)。
-
JS 引擎线程:执行 JavaScript 代码(始终只有一个,单线程!)。
-
定时器线程:管理 setTimeout、setInterval 等定时器。
-
事件监听线程:处理用户交互(点击、输入等)事件。
-
HTTP 网络请求线程:负责异步处理请求数据,最多可同时处理 5~7 个同源请求。
-
...
尽管浏览器本身是多线程的,JavaScript 代码的执行依然是单线程的。
二、JS 是“单线程”运行的,所以其中大部分代码都是“同步”的(例如:循环...)
- 所以在 JS 中千万不要写“死循环”、“死递归”...等操作,这些操作会一直占用 JS 引擎线程,导致后续其他的程序都无法执行
- 但是 JS 中也有部分“异步”操作的代码
- [异步微任务]
- requestAnimationFrame
- Promise.then/catch/finally
- async/await
- queueMicrotask 手动创建一个异步的微任务
- MutationObserver
- IntersectionObserver
- ...
- [异步宏任务]
- setTimeout/setInterval
- 事件绑定/队列
- XMLHttpRequest/Fetch
- MessageChannel
- ... JS中的异步操作是:借用浏览器的多线程机制,再基于EventLoop事件循环机制,实现的单线程异步效果!!
三、JS执行流程
- 浏览器加载页面,除了开辟堆栈内存外,还有创建了两个队列
- WebAPI:任务监听队列
- EventQueue:事件/任务队列
1.首先:当主线程自上而下执行代码过程中,如果遇到“异步”代码把异步任务放到WebAPl中去监听!
-
浏览器开辟新的线程去监听是否可以执行
-
不会阻碍主线程的渲染,它会继续向下执行同步的代码
2.其次:当异步任务被监测为可以执行了,也不会立即去执行,而是把其挪至到EventQueue中排队等待执行!
-
根据微任务还是宏任务,放在不同的队列中
-
谁先进来排队的,谁在各自队伍的最前面
PS:对于定时器来讲,设定一个等待时间,到时间后并不一定会立即去执行..
3.最后:当“同步代码”(同步宏任务)“执行完毕”,主线程空闲下来,此时会去EventQueue中把正在排队的异步任务,按照顺序取出来执行!
-
异步的微任务优先级比较高,不论其任务是先放入的,还是后放入的,只要有可执行的异步微任务,永远先执行它!
-
同样级别的任务,是谁先放入的「谁先到可执行」,谁先执行!
-
是要把任务拿到栈中执行,而且是交给主线程去执行,所以只要这个拿出来的任务没有执行完,也不会再去拿其他的任务!
上述就是:EventLoop事件循环机制