JavaScript事件循环:一次浏览器线程的"约会"指南

你是否曾好奇,为什么setTimeout有时候"不准时"?为什么Promise.then总能插队成功?今天,我们就来揭秘JavaScript中最核心的异步机制------事件循环(Event Loop),看看浏览器里的线程们是如何"约会"的。

一、进程与线程:浏览器里的"打工人"和"部门"

  • 进程:相当于一个完整的"公司",比如打开一个Chrome标签页就是创建了一个新公司。它包含了所有资源和员工(线程),从成立到倒闭(关闭标签)的整个生命周期。
  • 线程 :进程里的"打工人",比如负责和服务器聊天的HTTP线程、负责执行JS代码的引擎线程、负责画画的渲染线程

有意思的是,JS引擎线程渲染线程是对"冤家"------它们不能同时工作!就像公司里的两个部门抢会议室,一个用着另一个就得等着。这就是为什么JS是"单线程"的,同一时间只能干一件事。

二、异步:单线程的"时间管理大师"

JS既然是单线程,那遇到耗时任务(比如请求数据)怎么办?总不能干等着吧?于是它学会了"时间管理":

  • 先把同步代码全部执行完(这是主线任务)
  • 遇到异步代码,就把它暂时放到"任务队列"里排队
  • 等主线任务干完了,再去"任务队列"里取异步代码执行

这就像你在公司上班:先处理完手头的紧急工作(同步代码),再去看邮件(异步任务)。

三、Event Loop:异步任务的"优先级排序"

异步任务也分"高低贵贱",Event Loop就是负责给它们排优先级的"HR":

1. 微任务:办公室里的"关系户"

微任务是最优先处理的,相当于公司里的"关系户",包括:

  • Promise.then
  • process.nextTick(Node.js)
  • MutationObserver

这些任务会在同步代码执行完后立即插队执行,而且会一直执行到队列为空。

2. 宏任务:老老实实排队的"普通员工"

宏任务就得老老实实排队,包括:

  • setTimeout/setInterval
  • AJAX请求
  • I/O操作
  • UI渲染

3. 执行顺序:就像吃火锅

Event Loop的执行顺序可以类比吃火锅:

  1. 先吃主食(同步代码)
  2. 再吃小料(微任务)
  3. 然后涮肉(渲染页面)
  4. 最后煮面条(执行宏任务,开启下一轮循环)

四、代码实战:Event Loop的"狼人杀"

来看个经典例子,猜猜输出顺序:

javascript 复制代码
console.log('script start');
async function async1() {
  await async2()
  console.log('async1 end');
}
async function async2() {
  console.log('async2 end');
}
async1()
setTimeout(() => {
  console.log('setTimeout');
}, 0)
new Promise((resolve) => {
  console.log('promise');
  resolve()
}).then(() => {
  console.log('then1');
}).then(() => {
  console.log('then2');
});
console.log('script end');

正确答案

arduino 复制代码
script start
promise
script end
async2 end
async1 end
then1
then2
setTimeout

是不是很神奇?这里的关键是:await会先执行右边的代码,然后把后续代码扔入微任务队列。

五、await:异步世界的"插队小能手"

async/await是Promise的语法糖,但它有个特殊能力:

  1. 会把后续代码挤入微任务队列
  2. 浏览器会"提前"执行await后面的代码(相当于同步)

就像你在排队买奶茶,突然有个人拿着await的VIP卡,先点单(执行右边代码),然后去旁边等着(后续代码入微任务),等前面的人都买完了,他再回来取奶茶。

总结:Event Loop的"潜规则"

  1. 同步代码先执行(宏任务的一部分)
  2. 微任务队列清空后才会执行宏任务
  3. 每个宏任务执行完后,会检查微任务队列
  4. await后面的代码是微任务

理解了Event Loop,你就能解释为什么有些代码的执行顺序总是超出预期,也能写出更高效的异步代码。下次面试遇到这类问题,记得用"公司部门"

相关推荐
GISer_Jinger13 分钟前
Trae Solo模式生成一个旅行足迹App
前端·javascript
zhangbao90s14 分钟前
Intl API:浏览器原生国际化API入门指南
前端·javascript·html
s3xysteak27 分钟前
我要成为vue高手02:数据传递
前端·javascript·vue.js
文艺理科生1 小时前
Nuxt 状态管理权威指南:从 useState 到 Pinia
前端·javascript·vue.js
汪子熙1 小时前
解决 Node.js 无法获取本地颁发者证书问题的详细分析与代码示例
javascript·后端
秋秋小事2 小时前
React Hooks UseRef的用法
前端·javascript·react.js
辉长六加14 小时前
nodejs和vue安装步骤记录
前端·javascript·vue.js·npm·node.js
changuncle5 小时前
Angular初学者入门第三课——工厂函数(精品)
前端·javascript·angular.js
s3xysteak6 小时前
我要成为vue高手01:上下文
前端·javascript·vue.js