JavaScript宏任务和微任务、事件循环及经典案例

本文详细介绍了JavaScript的单线程特性及其原因,同步任务与异步任务的区别,以及宏任务和微任务的概念和执行顺序。通过具体案例分析了事件循环的工作流程,帮助理解JavaScript中的异步处理机制。

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

宏任务和微任务、事件循环

JavaScript是单线程的,也就是说,同一个时刻,JavaScript只能执行一个任务,其他任务只能等待。

为什么JavaScript是单线程的

js是运行于浏览器的脚本语言,因其经常涉及操作dom,如果是多线程的,也就意味着,同一个时刻,能够执行多个任务。

试想,如果一个线程修改dom,另一个线程删除dom,那么浏览器就不知道该先执行哪个操作。

所以js执行的时候会按照一个任务一个任务来执行。

为什么任务要分为同步任务和异步任务

试想一下,如果js的任务都是同步的,那么遇到定时器、网络请求等这类型需要延时执行的任务会发生什么?

页面可能会瘫痪,需要暂停下来等待这些需要很长时间才能执行完毕的代码

所以,又引入了异步任务。

  • 同步任务:同步任务不需要进行等待可立即看到执行结果,比如console

  • 异步任务:异步任务需要等待一定的时候才能看到结果,比如setTimeout、网络请求

宏任务和微任务

异步任务,又可以细分为宏任务和微任务。下面列举目前学过的宏任务和微任务。

宏任务、微任务的执行顺序

执行顺序:先执行同步代码,遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。

举个例子:

比如去银行办理业务排队,每一个办理业务的人就是一个个宏任务,当宏任务张三在柜台办理业务时,其它任务都需等待,当一个宏任务张三办理业务结束时,柜台职员询问他还要不要办理一张信用卡或者其他理财产品,那么这些询问的其它业务就是微任务,如果他还有其他业务,则其他人就需要等待张三办理完,也就是后边的宏任务还需要等待张三办理完微任务之后。

在当前的微任务没有执行完成时,是不会执行下一个宏任务的。

事件循环(Event Loop)

事件循环比较简单,它是一个在 "JavaScript 引擎等待任务","执行任务"和"进入休眠状态等待更多任务"这几个状态之间转换的无限循环。

引擎的一般算法:

  1. 当有任务时:

    • 从最先进入的任务开始执行。

  2. 休眠直到出现任务,然后转到第 1 步。

简单概括一下事件循环,就是

1.执行宏任务队列中第一个任务,执行完后移除它

2.执行所有的微任务,执行完后移除它们

3.执行下一轮宏任务(重复步骤2)

如此循环就形成了event loop,其中,每轮执行一个宏任务和所有的微任务

案例题分析

例题1:

console.log(1)

setTimeout(function() {
  console.log(2)
}, 0)

const p = new Promise((resolve, reject) => {
  resolve(4)
})
p.then(data => {
  console.log(data)
})

console.log(3)

下边分析一下执行顺序:

首先浏览器执行js进入第一个宏任务进入主线程, 遇到 console.log(1) 直接执行输出外层宏事件1

遇到 setTimeout  分发到宏任务队列中...

遇到 Promise,但由于new Promise没有输出事件,接着执行遇到.then

• 执行then 被分发到微任务Event Queue中

遇到最下边consile.log(3) 直接执行输出3

 宏任务执行结束,开始执行微任务 打印 data 的值 4

微任务执行完毕,执行第二轮宏事件,打印setTimeout里面内容 2

// 所以最终输出的结果顺序是: 1   3    4    2

例题2:

console.log(1)
setTimeout(function() {
  console.log(2)
  new Promise(function(resolve) {
    console.log(3)
    resolve()
  }).then(function() {
    console.log(4)
  })
})

new Promise(function(resolve) {
  console.log(5)
  resolve()
}).then(function() {
  console.log(6)
})

setTimeout(function() {
  console.log(7)
  new Promise(function(resolve) {
    console.log(8)
    resolve()
  }).then(function() {
    console.log(9)
  })
})

console.log(10)

首先浏览器执行js进入第一个宏任务进入主线程, 直接输出打印console.log(1) 
遇到setTimeout 分发到下一个宏任务队列。。。
遇到new Promise 输出打印console.log(5)  遇到.then 被分发到微任务Event Queue中...
遇到第二个setTimeout 分发到下一个宏任务队列。。。
遇到console.log(10) 直接输出打印
第一轮宏任务执行 结果是  1   5  10
接着开始执行第一轮中的微任务.then  输出打印console.log(6)

•执行第二轮宏事件,执行setTimeout
•先执行主线程宏任务,在执行微任务,打印'2,3,4'
•在执行第二个setTimeout,同理打印 '7,8,9'

//最终执行的结果顺序为: 1   5   10   6    2   3   4   7   8   9

例题3:

  new Promise((resolve, reject) => {
    resolve(1)

    new Promise((resolve, reject) => {
      resolve(2)
    }).then(data => {
      console.log(data)
    })

  }).then(data => {
    console.log(data)
  })

  console.log(3)

// 3    2   1

例题4:

console.log(1);

  setTimeout(function () {
      console.log(2)
    }, 1000);

  Promise.resolve()
      .then(function () {
        console.log(3);
      })
      .then(function () {
        console.log(4);
      })

  async function errorFunc() {
      try {
        await Promise.reject('error!!!')
      } catch (e) {
        console.log(5);
      }
      console.log(6);
      return Promise.resolve('errorFunc success')
    }

  errorFunc().then((res) => console.log(7))

  console.log(8);


//1  8  3  5  6  4  7   2

 例题5:

setTimeout(() => {
  console.log(1)
}, 0)
new Promise((resolve, reject) => {
  console.log(2)
  resolve('p1')

  new Promise((resolve, reject) => {
    console.log(3)
    setTimeout(() => {
      resolve('setTimeout2')
      console.log(4)
    }, 0)
    resolve('p2')
  }).then(data => {
    console.log(data)
  })

  setTimeout(() => {
    resolve('setTimeout1')
    console.log(5)
  }, 0)
}).then(data => {
  console.log(data)
})
console.log(6)

//2  3   6   p2    p1   1    4    5
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值