浏览器事件循环/主线程

45 阅读1分钟

自查问题

  1. 控制台会打印1吗,为什么
function loop() {
        Promise.resolve().then(loop);}setTimeout(() => {console.log(1)}, 0);loop();
  1. 页面有个link,当hover时样式会从灰变绿,现在在控制台加下面的脚本,会怎么样,hover还会变绿吗
while (true);
  1. 控制台的打印
Promise.resolve(1).then((x) => { console.log(x); return x + 1 }).then((x) => {console.log(x);})

Promise.resolve(10).then((x) => { console.log(x); return x * 10}).then((x) => {console.log(x);})

事件循环图

image.png 我们最终需要理解的目标就是上图。

事件循环

while (true) {
    if (execQueue.isNotEmpty()) {
                execQueue.pop().exec();
     }
 }

任务队列有任务就执行。

任务有如下几种:

  1. 任务队列: 所有事件,延时任务

  2. 微任务: promise回调,mutationObserver

微任务

特点是:只要当前callstack为空,就会清空微任务队列,因此有可能会阻塞渲染,永远不执行renderQueue的任务

Render Queue

渲染队列的任务就是完成一次渲染,渲染频率取决于硬件,可以简单理解每隔16ms,会向render queue放一个渲染任务。

回流

回流是计算元素布局信息的步骤。当页面resize或者读取某些属性时都会触发,这叫做强制回流。需要注意:强制回流会暂停执行js代码。

比如下面的代码会触发两次回流操作

div1.style.height = "200px";
var height1 = div1.clientHeight; // <-- layout 1
div2.style.margin = "300px";
var height2 = div2.clientHeight; // <-- layout 2 

而将读写分离开,只会触发一次操作

div1.style.height = "200px";
div2.style.margin = "300px";
var height1 = div1.clientHeight; // <-- layout 1
var height2 = div2.clientHeight;

参考

xnim.me/blog/javasc…