Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

面试:为什么transform不影响页面的性能问题? #175

Open
wuweijia opened this issue Aug 29, 2024 · 0 comments
Open

面试:为什么transform不影响页面的性能问题? #175

wuweijia opened this issue Aug 29, 2024 · 0 comments

Comments

@wuweijia
Copy link
Owner

面试:为什么transform不影响页面的性能问题?

这个篇幅不会过多的讲浏览器原理,本文是在有一些浏览器渲染原理的知识点下的总结。

首先一个页面是服务端传回的字符串,所以他并不能直接渲染成一个页面,浏览器拿到这个字符串要进行一系列的解析。我们可以从从浏览器渲染过程找到问题的答案。

浏览器渲染页面的过程,可以大致分为以下几个步骤

  1. 解析(Parsing)
    HTML 解析: 浏览器首先会将 HTML 文档解析成一个树状结构,称为 DOM 树。DOM 树表示文档的内容和结构,其中每个 HTML 标签都会被转换为一个 DOM 节点。
    CSS 解析: 浏览器同时会解析所有的 CSS 文件和内联样式,生成 CSSOM。CSSOM 树描述了页面的样式规则。
  2. 构建渲染树(Render Tree)
    生成渲染树: 浏览器将 DOM 树与 CSSOM 树结合起来,生成 渲染树(Render Tree)。渲染树中的每个节点对应一个页面上可见的元素,包含了该元素的视觉信息(如位置、大小、颜色等)。
    排除不可见元素: 像 标签中的内容或使用 display: none 的元素不会出现在渲染树中。
  3. 布局(Layout)
    计算布局: 在布局阶段,浏览器根据渲染树中的信息计算出每个元素的确切位置和大小。这个过程有时也被称为 reflow 或 layout。
    流式布局模型: 浏览器使用流式布局模型来确定每个元素的几何形状和在屏幕上的位置。对于复杂的布局,浏览器可能需要多次计算。
  4. 绘制(Painting)
    绘制过程: 在绘制阶段,浏览器会根据渲染树和布局信息,将每个节点的视觉信息(如颜色、边框、阴影等)绘制到屏幕的各个图层上。这一步生成了绘制列表。
    绘制顺序: 浏览器按从后到前的顺序绘制元素,以确保遮盖关系正确处理。
  5. 分层与合成(Layering and Compositing)
    • 分层: 浏览器将页面划分为多个图层(layers),这些图层可能对应于不同的页面元素,特别是那些需要独立处理的元素(如 transform、opacity、position: fixed 等)。
    • 生成绘制列表(Display List):在这一阶段,每个图层生成其对应的绘制列表,其中包含了所有需要绘制的内容和指令,一般我们叫指令集
    • 合成线程处理:合成线程将绘制列表中的信息传递给 GPU。GPU 根据这些指令生成每个图层的位图。位图是图层的像素数据,用于实际的图像显示。合成过程可能包括滚动处理、动画处理等。
    • 渲染:生成的位图被合成线程合成在一起,形成最终的页面图像,并将其传送到显示器上。
  6. 显示(Displaying)
    显示到屏幕: 最后一步,经过合成后的图像通过浏览器的渲染管道传输到显示器上,这就是用户最终看到的页面内容。

经过以上的流程我们发现,整个流程下来,第五步提到了动画处理流程:这里面有一个关键的信息是,合成线程,1234这四个步骤是渲染主线程完成的,到了 5 这里有合成线程参与了进来,说明在第五步,有些事情渲染线程是没有参与的,其中就包括动画的合成和执行。

为了验证这一猜想,我们可以用如下代码来测试

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<style>
		.ball {
			width: 50px;
			height: 50px;
			border-radius: 50%;
			position: absolute;
		}

		.ball1 {
			background-color: #3498db;
			animation: moveRight 2s linear infinite;
			will-change: transform;
			top: 100px;
		}

		@keyframes moveRight {
			0% {
				transform: translateX(0);
			}

			100% {
				transform: translateX(300px);
			}
		}

		.ball2 {
			background-color: #e74c3c;
			animation: moveLeft 2s linear infinite;
			will-change: left;
		}

		@keyframes moveLeft {
			0% {
				left: 0;
			}

			100% {
				left: 300px;
			}
		}
	</style>
</head>

<body>
	<button onclick="busyWork()">死循环五秒</button>
	<div class="container">
		<div class="ball ball1"></div>
		<div class="ball ball2"></div>
	</div>
	<script>
		function busyWork() {
			let start = Date.now();
			while (Date.now() - start < 5000) {
			}
		}
	</script>
</body>

</html>

结果我们会发现,在执行死循环五秒的过程中,红色的球,停止了移动,而蓝色的球没有影响。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant