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

相关推荐
To_OC8 小时前
LC 131 分割回文串:刚学回溯时,我连怎么切字符串都想不明白
javascript·算法·leetcode
To_OC10 小时前
LC 42 接雨水:暴力超时卡半天?前后缀数组一用就通了
javascript·算法·leetcode
小林ixn10 小时前
从 ??= 到 onKeyDown:一个 React 组件的“自我修养”
前端·javascript·react.js
এ慕ོ冬℘゜11 小时前
前端实战:jQuery 多条件联合搜索(标题模糊查询 + 日历时间段筛选)
前端·javascript·jquery
随心点儿11 小时前
js postMessage 实现跨域发送消息-应用示例
javascript·ecmascript·postmessage
kyriewen13 小时前
我让AI改一个bug——它偷偷动了5个我没让它碰的地方
前端·javascript·ai编程
gis开发之家17 小时前
《Vue3 从入门到大神35篇》Vue3 源码详解(五):effect 依赖收集原理——track 与 trigger 是如何工作的?
javascript·typescript·前端框架·vue3·vue3源码
橘子星18 小时前
我一个前端切图仔,凭什么能在浏览器里跑大模型?
前端·javascript·前端框架
半个落月18 小时前
用 LangChain JS 做可控写作实验:理解温度参数、提示词与异步调用
javascript·人工智能·后端
观远数据18 小时前
Excel到数据资产池:文件数据入湖的治理规范怎么建
前端·javascript·excel