Web 浏览器之事件循环 Event Loop

一、

要了解事件循环Event Loop,首先我们必须明白以下几点

1、javascript是一门单线程语言

   在最新的HTML5中提出了Web-Worker,但javascript是单线程这一核心仍未改变

   是单独开启了一条js线程,即workerjs线程和js主线程,

   二者相互独立,通过postmessage通信,worker只是负责复杂运算,但不能操作DOM,有诸多限制

   有了多线程的形,但不具备多线程的神,不具备线程间通信的能力

2、JS和元素渲染在同一个线程中工作

   EventLoop在其周期内执行任务,我们的JS代码必须以某种方式与DOM配合使用

   获取元素的大小,添加属性,绘制一些弹出窗口,等等。它应该使界面活跃起来。它为元素图形 添加了一些限制。

   在其中一个线程中运行两个线程来执行JS,在另一个线程中使用CSS进行渲染,这很复杂,因为它需要大量的代码同步,否则可能会导致执行不一致。

   这就是为什么JS和元素渲染在同一个线程中工作

   这意味着我们应该在模式中添加“渲染”。因为这不是一个单一的操作,所以最好使用单独的队列。我们称之为渲染队列

3、屏幕更新(事件循环与帧密不可分)

    事件循环不仅执行JS代码,还计算新的帧

    浏览器试图尽快在页面上显示更改。我们确实有一些限制:

    硬件限制:屏幕刷新率;

    软件限制:操作系统、浏览器、节能设置等。

    大多数现代设备(和应用程序)支持每秒60帧。

    大多数浏览器都试图以这种特定的速度更新屏幕。

    因此,我们将在本文中使用60 FPS,但最好记住,确定的速率可能会有所不同。

    对于我们的事件循环来说,这意味着如果我们想要保持60FPS,我们的任务有16.6ms的时隙

    可以简单理解为我们以60 FPS在循环

4、队列和栈

    队列是先进先出,栈是先进后出

5、微任务、宏任务、DOM渲染

     宏任务:DOM渲染后触发,如:setTimeout,setInterval,Ajax,DOM事件

     微任务:DOM渲染前触发,如:Promise,async/await

     微任务执行时机要比宏任务要早

所以我们可以理解为事件循环(Event Loop)有如下图所示的一个无限循环,有无数的任务等着去执行

 

二、

有了这无数的任务,我们怎么来处理这些任务呢?他们必然是有优先级的,要在不同的队列去执行

微任务队列,宏任务队列,渲染队列

事件循环就会从不同的队列中取对应的任务

1、渲染队列(Render Queue)

每个帧渲染可以分为几个阶段,每个阶段可分为子阶段,我们大致可以如下图所示理解这个渲染

位置大小-->样式-->布局-->绘制-->合成

 优先级最高

2、微任务队列(Microtask Queue)

顾名思义这个里面存放的都是些微任务,什么是微任务(MicroTask)?

Promises 或者 MutationObserver(观察的是DOM) callbacks等

微任务是特别的,主要特点是,一旦调用堆栈变空,它们就会被执行优先级高

3、宏任务队列(Macrotask Queue)

顾名思义这个里面存放的都是宏任务,什么是宏任务(MacroTask也叫Task)?

Web API、Script代码块、UI样式的计算等

宏任务的特点就是耗时比较久,优先级低,排队等着执行

4、调用堆栈(Call Stack)

调用堆栈是一个列表,显示当前正在调用哪些函数,以及当前函数完成执行后将在何处进行转换。

故我们可以用下图简单示意

 参考资料:

https://xnim.me/blog/javascript-browser-event-loop-layout-paint-composite-call-stack

posted @ 2022-04-18 11:28  小菜看代码  阅读(147)  评论(0编辑  收藏  举报