# 一、JS事件循环机制
1.1 定义
JS中的事件循环机制是 一种异步执行的机制, 主要用于处理代码中异步任务
主要包括宏任务和微任务两个阶段
当代码遇到一个异步任务时,比如定时器、事件监听等。js会将该任务交给浏览器的事件循环线层进行处理,等待该任务处理完成后再将其添加到执行队列中,等待js引擎空闲时再执行
1.2 三个主要组成部分
(1)调用栈,用于存储js代码的执行顺序
(2)任务队列,用于存储异步代码的回调函数
(3)事件循环线程,用于循环监听任务队列中是否有任务需要执行,如果有则添加到调用栈中执行
1.3 执行流程
当代码遇到一个异步任务时,会将该任务的回调函数,添加到任务队列中;
当调用栈中的代码执行完成后,事件循环线程会从任务队列中取出一个任务添加到调用栈中执行;
这个任务过程是一直重复的,直到任务队列中没有任何的任务为止。
注意:任务队列中的任务被执行顺序,有先进先出的原则,先添加到任务队列中的任务先执行
二、宏任务/微任务
JavaScript 事件循环是基于宏任务(macrotask)和微任务(microtask)的概念。
2.1 同步任务 / 异步任务
JavaScript 是单线程语言,所谓的 "执行线程" 指的是在一个时间点上,只有一个代码片段在被执行。
2.1.1 同步任务
在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。
2.1.2 异步任务(宏任务 / 微任务)
不进入主线程、而进入"任务队列"(task queue)的任务,只有当主线程上的同步任务执行完毕,"任务队列"开始通知主线程,才可以执行这些异步任务。
2.2 宏任务 / 微任务
JavaScript中的异步任务可分为宏任务和微任务
2.2.1 宏任务(Macro Task)
- 脚本 (script)
- 定时器:setTimeout()/setInterval()
- setImmediate (Node.js 环境)
- 事件处理函数(如点击按钮、提交表单)
- I/O 操作回调
- UI 渲染
2.2.2 微任务(Micro Task)
- process.nextTick (Node.js 环境)
- Promise的回调(Promise本身同步,then/catch的回调函数是异步的)
- MutationObserver(DOM变动观察器)
- Object.observe (已废弃)
2.2.3 执行顺序(略)
- 执行当前宏任务中的全部代码
- 执行完成后,立即执行在当前宏任务中产生的左右微任务
- 微任务执行完成后,进入下一个宏任务循环
2.2.4 执行过程(详)
-
执行执行栈中的同步代码
-
检查微任务队列,如果有,通过事件循环方式,推到事件执行栈中执行,执行完毕后,再检查微任务队列,直到执行微任务队列中的所有任务
-
检查宏任务队列,如果有排队的任务,通过事件循环推到执行栈中执行,直到所有宏任务执行完毕,就执行完整个代码块了
async/await 与 宏任务/微任务
async 是同步任务,立即执行
await 后面的代码是异步的,微任务
会立即执行右边的代码,执行完成后再执行后面的代码
async function async1() {
console.log(1)
await async2()
console.log(2)
}
async function async2() {
console.log(3)
}
console.log(4)
setTimeout(() => {
console.log(5)
}, 0)
async1()
// 输出顺序 4 1 3 2 5