likes
comments
collection
share

JS的事件执行机制

作者站长头像
站长
· 阅读数 66

靡不有初,鲜克有终

不积跬步无以至千里

1、为什么js是单线程?

js作为主要运行在浏览器的脚本语言,js主要用途之一是操作DOM

假设如果js同时有两个线程,同时对同一个DOM进行操作,这时浏览器应该听哪个线程的,如何判断优先级?

为了避免这种问题,js必须是一门单线程语言,并且在未来这个特点也不会改变。

2、js执行机制

既然js是单线程,那就像只有一个窗口的银行,客户需要排队一个一个办理业务,同理js任务也要一个一个顺序执行。

如果一个任务耗时过长,那么后一个任务也必须等着。

那么问题来了,假如我们想浏览新闻,但是新闻包含的超清图片加载很慢,难道我们的网页要一直卡着直到图片完全显示出来?

因此聪明的程序员将任务分为两类:

  • 同步任务
  • 异步任务

当我们打开网站时,网页的渲染过程就是一大堆同步任务,比如页面骨架和页面元素的渲染;

而像加载图片音乐之类占用资源大耗时久的任务,就是异步任务

直接上图:

JS的事件执行机制

导图要表达的内容用文字来表述的话:

  • 同步和异步任务分别进入不同的执行"场所",同步的直接进入主线程,异步的进入Event Table并注册函数;
  • 当指定的事情完成时,Event Table(事件列表)会将这个函数移入Event Queue(事件队列);
  • 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行;
  • 上述过程会不断重复,也就是常说的Event Loop(事件循环)。

我们不禁要问了,那怎么知道主线程执行栈为空啊?(不用你管)

js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。

3、异步任务的宏与微

异步任务分为 宏任务(macrotask) 与 微任务 (microtask)

不同的API注册的任务会依次进入自身对应的队列中,然后等待 Event Loop 将它们依次压入执行栈中执行。

JS的事件执行机制

4、Event Loop(事件循环)

Event Loop(事件循环)中,每一次循环称为 tick, 每一次tick的任务如下:

  • 执行栈选择最先进入队列的宏任务(通常是script整体代码),如果有则执行
  • 检查是否存在 Microtask,如果存在则不停的执行,直至清空 microtask 队列
  • 更新render(每一次事件循环,浏览器都可能会去更新渲染)
  • 重复以上步骤

宏任务A > 所有微任务 > 宏任务B,如下图所示:

JS的事件执行机制

从上图我们可以看出:

1、将所有任务看成两个队列:执行队列与事件队列。

2、执行队列是同步的,事件队列是异步的,宏任务放入事件列表,微任务放入执行队列之后,事件队列之前。

3、当执行完同步代码之后,就会执行位于执行列表之后的微任务,然后再执行事件列表中的宏任务

5、举个栗子

      setTimeout(function () {
        console.log(1)
      })
​
      new Promise(function (resolve, reject) {
        console.log(2)
        resolve(3)
      }).then(function (val) {
        console.log(val) // 微任务1
      })
​
      new Promise(function (resolve, reject) {
        console.log(4)
        resolve(5)
      }).then(function (val) {
        console.log(val) // 微任务2
      })
​
      console.log(6)

解析一下:

第一步:宏任务A

(直接整体js代码就是第一个宏任务)

1、script中的同步代码依次执行

2、第一个new Promise中的console.log(2),得到2

3、第二个new Promise中的console.log(4),得到4

4、外面的script同步代码console.log(6),得到6

此次宏任务执行完毕;

第二步:所有可执行的微任务

1、then后面的属于Promise微任务,全部依次执行,得到3, 5

第三步:宏任务B

1、执行新的宏任务,得到1

最后,可以很轻松猜出或者说是写出正确答案:2,4,6,3,5,1

6、总结:

1、js主要用途之一是操作DOM,所以是一定也必须是单线程;

2、js执行机制分为同步任务和异步任务;

3、异步任务分为 宏任务(macrotask) 与 微任务 (microtask);

4、Event Loop(事件循环)的执行顺序:

执行同步代码 ---> 所有微任务 ---> 宏任务A ---> 所有 新产生的 微任务 ---> 宏任务B

执行流程如图:

JS的事件执行机制

此文章仅用于自己的理解记忆,参考的文章已经写得非常详细了,

参考链接:

这一次,彻底弄懂 JavaScript 执行机制

Js 的事件循环(Event Loop)机制以及实例讲解

setTimeout+Promise+Async输出顺序?很简单呀!

转载自:https://juejin.cn/post/7038806892587515911
评论
请登录