JS事件循环机制、调用栈以及任务队列

本文深入解析JavaScript的单线程特性及其事件循环机制,阐述了执行上下文栈、宏任务与微任务的区别,以及它们如何影响代码的执行顺序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、JS单线程
众所周知,JavaScript语言的一大特点单线程。JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

所以,为了避免复杂性,单线程成了这门语言的核心特征 !!

二、JS事件循环机制(event loop)

JavaScript 引擎创建了执行上下文栈来管理执行上下文。可以把执行上下文栈(call stack)认为是一个存储函数调用的栈结构,遵循先进后出的原则。
在这里插入图片描述
上图为事件循环机制图,流程如下:

  • 所有同步任务排队在主线程上执行,形成相应的堆和执行栈(call stack)
  • 如果遇到异步操作,交给浏览器模块异步进程进行处理(WEB API)
  • 异步进程处理完毕(DOM事件触发、Ajax返回、Timer出发等),将相应的异步回调事件任务推入任务队列(callback queue)
  • ”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,按队列顺序进入执行栈,开始执行
  • 重复执行前面的步骤,称为事件循环(event loop)

三、任务队列

上图的任务队列属于同一类型任务,根据队列顺序依次在“执行栈”中执行。如果存在不同类型,执行顺序会按照优先级依次执行。

任务类型:

macrotasks(宏任务): setTimeout, setInterval, setImmediate, I/O, UI rendering
microtasks(微任务): process.nextTick, Promise, MutationObserver

上述我们知道,setTimeout是’宏任务’,Promise是‘微任务’
在这里插入图片描述
通过上图我们可以看出:宏任务的优先级高于微任务,每一个宏任务执行完毕都必须将当前的微任务队列清空,如果队列中还存在宏任务,依次执行

四、案例

<script>
  console.log(1)
  setTimeout(() => {
    console.log(2)
  },0)
  new Promise((resolve,reject) => {
    console.log(3)
    resolve()
  }).then(res => {
    console.log(4)
  })
  console.log(5)
</script>

以上代码会输出:1 3 5 4 2

为什么不应该是:1 3 5 2 4

分析:

  1. script 执行第一次宏任务
  2. 首先同步执行,输出1
  3. 遇到setTimeout 回调 扔到队列 macrotasks(宏任务)第二次宏任务中
  4. 同步执行Promise,输出3,回调 then 扔到队列 microtasks(微任务)中
  5. 最后同步执行,输出5
  6. 第一次宏任务执行完毕,执行微任务 Promise then 回调,输出4
  7. 最后执行第二次宏任务,setTimeout 回调 输出2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端小小白zyw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值