Renderer Process
渲染进程包括
- Compositor Thread
- Main Thread(主线程),我们基本上都是和它打交道
- Compositor Tile Workers
Rendering
动画
<!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>
<style>
body {
position: relative;
}
.box {
width: 100px;
height: 100px;
background: #94a3b8;
}
.one {
position: absolute;
background: #818cf8;
animation: slide 3s infinite;
}
@keyframes slide {
from {
top: 0px;
}
to {
top: 500px;
}
}
</style>
</head>
<body>
<div class="box one"></div>
</body>
</html>
当使用上面的的代码做animation时, 浏览器Performance面板有以下数据
可以看到每个frame或者每16.7ms, Main Thread都会执行Layout/painting, 在没有大规模计算的情况下动画是能够保持60帧/s.
计算
一旦有某些脚本设计大量计算,这些会造成layout/paint的动画就可能会掉帧,或者卡顿。添加以下代码模拟计算
// 省略...
<button id="btn">计算</button>
<script>
const btn = document.querySelector("#btn");
btn.addEventListener("click", () => {
// 模拟计算
for (let i = 0; i < 10000; i++) {
console.log("");
}
});
</script>
点击按钮后,动画会卡顿,帧率59下降到55fps
此时Performance面板的数据是这样子的,3900ms~4400ms, 事件回调执行,回调函数执行计算任务阻塞了rendering,使浏览器没有机会执行渲染任务
优化
大量计算会阻塞rendering, 我们可以使用requestAnimationFrame/requestIdleCallback将大任务分解成小任务,(raf callback会在rendering之前执行, ric在rendering之后执行), 点击按钮,帧率维持在59fps
<script>
const btn = document.querySelector("#btn");
btn.addEventListener("click", () => {
let i = 0;
function workLoop() {
if (i >= 10000) {
console.log("完成");
return;
}
for (let j = 0; j < 100; j++) {
i++;
console.log("");
}
requestAnimationFrame(workLoop);
}
requestAnimationFrame(workLoop);
});
</script>
此时的Performance面板, 可以看到大计算任务分解成一个个小的raf里面,每一帧都有机会让浏览器layout/paint, 这样动画更加流畅。利用raf, 我们也可以优化长列表处理, 长列表分成一个个小列表处理。
高性能动画[3]
这部分单独再复习
尽管raf/ric能够活得流畅的动画效果,但是依然存在问题,每一帧都存在layout/paint, 我们应该尽可能避免在动画过程中发生layout/paint(重排/重绘),
拿上面的例子来说, 我们可以使用CSS transform属性移动元素, 而不是top left等, 使用以下代码比较tranform和top
<!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>
<style>
body {
position: relative;
}
.box {
width: 100px;
height: 100px;
background: #94a3b8;
}
.one {
position: absolute;
left: 400px;
background: #818cf8;
animation: slide-transform 3s infinite;
}
.two {
position: absolute;
left: 600px;
background: #fb7185;
animation: slide-top 3s infinite;
}
#btn {
position: absolute;
right: 0;
}
@keyframes slide-transform {
from {
transform: translateY(0px);
}
to {
transform: translateY(500px);
}
}
@keyframes slide-top {
from {
top: 0;
}
to {
top: 500px;
}
}
</style>
</head>
<body>
<div class="box one">transform</div>
<div class="box two">top</div>
<button id="btn">计算</button>
<script>
const btn = document.querySelector("#btn");
btn.addEventListener("click", () => {
// 模拟计算
for (let i = 0; i < 10000; i++) {
console.log("");
}
});
</script>
</body>
</html>
当我们按下按钮的时候,右边的红色块(使用top属性做动画), 会有明显的卡顿,而左边的不会
绿框框说明发生了painting
使用transform
可以看到, animtion中transform移动元素,不会有layout/paint, 因此点击了计算按钮,这个动画依然流畅
使用top属性
由于每一帧都要有layout/paint, 当有大量计算任务时, 就会阻塞rendering, 因此造成动画卡顿
参考
- The Anatomy of a Frame aerotwist.com/blog/the-an…
- Inside look at modern web browser (part 3)developer.chrome.com/blog/inside…
- How the browser renders a web page? medium.com/jspoint/how…
- How to create high-performance CSS animationsweb.dev/animations-…
- How the browser renders a web page? — DOM, CSSOM, and Rendering medium.com/jspoint/how…