🥇浏览器渲染时机解密:从两段颜色变化代码看事件循环

536 阅读1分钟

代码

今天,代码干货,上菜🥬。

先来看这段代码🕶️:

document.body.style.background = 'red';
console.log(1)
Promise.resolve().then(() => {
  console.log(2)
  document.body.style.background = 'yellow';
})
console.log(3); 

浏览器渲染的颜色是什么样子的,打印的结果是什么样子的?停下来,先思考3秒钟。

1.gif

这结果出来了:输出 1, 3, 2, 黄。

再来看一段代码🕶️:

document.body.style.background = 'red';
console.log(1)
setTimeout(() => {
  console.log(2)
  document.body.style.background = 'yellow';
})
console.log(3);

同样先思考3秒钟,想出打印应该是什么顺序,以及颜色渲染应该是咋样的。

1.gif

结果是:1,3,2 页面是先红再黄。


分析

细说:为什么红色没有渲染出来,直接就是黄色了?

document.body.style.background = 'red';
console.log(1)
Promise.resolve().then(() => {
  console.log(2)
  document.body.style.background = 'yellow';
})
console.log(3); 

image.png

image.png

image.png


细说:为什么这段代码就可以先红,后黄?

document.body.style.background = 'red';
console.log(1)
setTimeout(() => {
  console.log(2)
  document.body.style.background = 'yellow';
})
console.log(3);

image.png

image.png

image.png

image.png

俩段代码,一个Promise,一个setTimeout,可以看得出事件循环浏览器渲染不同影响

Promise:

微任务Promise会阻塞渲染,

document.body.style.background = 'red';
Promise.resolve().then(() => {
  document.body.style.background = 'yellow';
});

记一个口诀(遇事不决,记口诀):同步任务 -> 微任务 -> 渲染 -> 宏任务。

也就是说,微任务在同步任务后紧接着执行,并且,早于浏览器渲染

所以也就得出,为什么Promise这段代码不会出现红色闪烁。也就印证了上面的话:等微任务队列执行完后才会进入渲染阶段。

setTimeout:

那对于setTimeout来讲,先看代码:

documnet.body.style.background = 'red';
setTimeout(() => {
  document.body.style.background = 'yellow';
})

对于setTimeout来讲,就是说它可以等渲染完成后执行,就是允许中间渲染。

记一个口诀(遇事不决,记口诀):同步任务 -> 微任务 -> 渲染 -> 宏任务。