0
点赞
收藏
分享

微信扫一扫

AJAX-事件循环(超详细过程)

一.概念

JS有一个基于事件循环的并发模型,事件循环负责执行代码、收集和处理事件以及执行队列中的子任务

定义:执行代码和收集异步任务的模型,在调用栈空闲,反复调用任务队列里回调函数的执行机制,就叫时间循环。

原因:JS是単线程,为了让耗时的代码不阻塞其他代码运行,设计了事件循环模型

二、事件循环-执行过程

AJAX-事件循环(超详细过程)_回调函数

注意:浏览器多线程,JS才是单线程

详细例子说明(超详细)

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>事件循环</title>
</head>

<body>

  <script>
    /**
     * 目标:阅读并回答执行的顺序结果
    */
    console.log(1)
    setTimeout(() => {
      console.log(2)
    }, 0)
    console.log(3)
    setTimeout(() => {
      console.log(4)
    }, 2000)
    console.log(5)

  </script>
</body>

</html>

AJAX-事件循环(超详细过程)_调用栈_02

第一行代码,是同步代码,放入调用栈里面立即执行,控制台打印:1,执行完以后立马出栈

AJAX-事件循环(超详细过程)_回调函数_03

第二行代码是一个异步代码,放入宿主环境,宿主环境发现是一个零秒的计时器,立马把这段代码推入任务队列当中,所以控制台此时并没有打印2,因为它此时在任务队列当中排队。

AJAX-事件循环(超详细过程)_任务队列_04

第三段代码,是一个同步代码,放入调用栈里立即执行,控制台打印3,并出栈。

AJAX-事件循环(超详细过程)_回调函数_05

第四段代码是异步代码,放入宿主环境里面等待2秒,在这2秒当中JS引擎会继续往下执行代码,由于第五段代码是同步代码,所以放入调用栈里面立即执行,控制台打印5,然后立马出栈。

AJAX-事件循环(超详细过程)_调用栈_06

当调用栈是空闲的时候,它会一直反复的尝试到任务队列里面调用要执行的回调函数

AJAX-事件循环(超详细过程)_任务队列_07

推入调用栈以后,立马执行该代码,打印2,然后出栈。

AJAX-事件循环(超详细过程)_调用栈_08

当宿主环境里的2秒过去以后,立马推入任务队列

AJAX-事件循环(超详细过程)_回调函数_09

此时调用栈处于空闲状态,到任务队列里面调用要执行的回调函数,推入到调用栈以后,立马执行,控制台打印4,然后出栈

上面是我们手工结果,我们运行代码看看结果是不是这样

AJAX-事件循环(超详细过程)_任务队列_10

结果正确!

三、宏任务与微任务

1.介绍

ES6之后引入了Promise对象,让JS引擎也可以发起异步任务

异步任务分为:

宏任务:由浏览器环境执行的异步代码

微任务:由JS引擎环境执行的异步代码

2.宏任务与微任务的代码

宏任务:

AJAX-事件循环(超详细过程)_回调函数_11

微任务:

AJAX-事件循环(超详细过程)_调用栈_12

注意:Promise本身是同步的,而then和catch回调函数是异步的

3.详细例子说明(超详细)

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>微任务与宏任务</title>
</head>

<body>
  <script>
    /**
     * 目标:阅读并回答打印的执行顺序
    */
    console.log(1)
    setTimeout(() => {
      console.log(2)
    }, 0)
    const p = new Promise((resolve, reject) => {
      console.log(3)
      resolve(4)
    })
    p.then(result => {
      console.log(result)
    })
    console.log(5)
  </script>
</body>

</html>

AJAX-事件循环(超详细过程)_回调函数_13

第一段是同步代码,放入调用栈中直接打印1,然后出栈

AJAX-事件循环(超详细过程)_调用栈_14

第二段是异步代码,放入宿主环境中,因为是0秒倒计时,且是宏任务,所以放入宏任务队列当中

AJAX-事件循环(超详细过程)_任务队列_15

第三段代码是同步代码,放入调用栈中理解执行,控制台打印3,resolve(4)是标记Promise处于成功状态

AJAX-事件循环(超详细过程)_回调函数_16

第四段代码p.then是同步的放入调用栈中,里面的回调函数是异步代码,且是微任务,所以放入微任务队列中

AJAX-事件循环(超详细过程)_调用栈_17

第五段代码是同步代码,放入调用栈中立即执行,控制台打印5,然后出栈

AJAX-事件循环(超详细过程)_任务队列_18

AJAX-事件循环(超详细过程)_回调函数_19

此时所有的同步代码都已执行完成,调用栈空闲,会反复的尝试到任务队列里面调用要执行的回调函数,由于微任务更接近JS引擎,所以优先调用微任务队列里面的回调函数,然后在调用栈里理解执行,控制台打印4,然后出栈

AJAX-事件循环(超详细过程)_调用栈_20

AJAX-事件循环(超详细过程)_调用栈_21

由于微任务队列已经清空了,所以开始调用宏任务里的回调函数(必须先清空微任务队列里的回调函数),然后在调用栈里立即执行打印2,然后出栈

让我们看看执行的结果是不是这样

AJAX-事件循环(超详细过程)_调用栈_22

对啦!

四、总结

AJAX-事件循环(超详细过程)_任务队列_23

当然还有我们的模型图

AJAX-事件循环(超详细过程)_回调函数_24

AJAX-事件循环(超详细过程)_任务队列_25

AJAX-事件循环(超详细过程)_回调函数_26





举报

相关推荐

0 条评论