前言
在构建高效、流畅的网页应用时,了解浏览器的渲染流程及其背后的引擎工作原理至关重要。今天我们将深入探讨渲染引擎与JavaScript引擎的运行机制,以及它们是如何影响页面性能的,该怎样来优化我们的性能
浏览器的内核
浏览器内核主要由渲染引擎和JavaScript引擎这两大部分组成,它们共同决定了浏览器如何处理和展示网页内容,以及如何响应用户与网页的交互。
渲染引擎:从代码到视觉的桥梁
渲染引擎负责将HTML、CSS和JavaScript转换为用户可见的图像。其工作流程大致分为以下几个步骤:
- 解析HTML:通过DOM解析器将HTML文档转换为可操作的对象模型——DOM树。
- 解析CSS:CSS解析器将CSS代码转换为CSS对象模型(CSSOM)树,描述了文档的样式信息。
- 生成渲染树:结合DOM树与CSSOM树,生成渲染树(Render Tree),只包含需渲染的元素及相应样式。
- 布局(Layout) :计算渲染树中每个节点的确切位置和尺寸,形成布局树(Layout Tree)。
- 绘制(Paint) :将布局树的各个节点绘制到屏幕上,这一过程可能涉及硬件加速,即由CPU调度GPU完成。
- 合成(Composite) :将不同的图层组合成最终的页面视图。
JavaScript引擎:动态交互的驱动力
JavaScript引擎则专注于执行JavaScript代码。JavaScript是一种单线程语言,在一定时间内它只能执行一个任务,所以会造成浏览器的阻塞。所以我们一般将js部分放在最底部,或者也可以使用异步或者延迟加载的方法,使其能够更快的加载完。JavaScript引擎独立于渲染引擎运行,但能够与之交互,如修改DOM或CSSOM,从而触发页面重绘或重排。
重绘与重排
重绘(Repaint)
当页面元素的外观发生变化,但不影响其几何尺寸时,如颜色或背景色改变,浏览器需要重新绘制该元素。重绘消耗掉性能较重排来说是要小点的。
重排(Reflow)
重排,也称为布局重计算,发生在页面元素的几何属性(如宽度、高度或位置)改变时,这会导致浏览器重新计算受影响元素及其子元素的布局。重排是更昂贵的操作,因为它不仅涉及布局的重新计算,还可能引发后续的重绘。例如,修改元素的宽度可能会导致其下方所有元素的位置调整。
如何进行性能优化
优化DOM操作
- 减少DOM操作:频繁操作DOM会导致大量回流和重绘,极大地浪费了浏览器性能。当我们要进行多次DOM操作时,我们应该尽量合并多次操作修改为一次操作。 例如:
<script>
for (var count = 0; count < 10000; count++){
document.getElementById('container').innerHTML += '<span>测试</span>'
}
</script>
像这段代码,我们要进行10000次的DOM操作,电脑直接给转冒烟了都干不完。因此我们可以首先进行拼接,拼接完成后再进行一次DOM操作就可以了。如下:
<script>
let container = document.getElementById('container');
let content = ''
for (var count = 0; count < 10000; count++){
content += '<span>测试</span>'
}
container.innnerHTML = content
</script>
- 使用DocumentFragment:在内存中创建一个DOM片段,完成所有修改后再一次性添加到文档中,减少重排次数。
<script>
let container = document.getElementById('container');
// 文档碎片 像个伪元素,可以像真实DOM一样挂载节点
let content= document.createDocumentFragment()
for (var count = 0; count < 10000; count++){
let oSpan = document.createElement('span')//DOM节点对象
oSpan.innerHTML = '测试'
// 将span节点挂载到文档碎片上,但节点并没有挂载到页面上
content.appendChild(oSpan)
}
// 一次将文档碎片节点挂上去
container.appendChild(content)
</script>
利用CSS与布局
- 避免使用强制性重排的CSS属性:如避免修改影响布局的属性(width、height、margin等),改用transform(平移、旋转、缩放)等不会触发回流的属性。
- 合理利用CSS选择器:复杂的选择器会影响样式计算效率,简化选择器能提升页面加载速度。 根据选择器的优先级,我们尽量少用标签选择器
- 关注可以通过继承实现的属性:CSS继承允许某些属性值从父元素传递给子元素,如果一个属性被定义为可继承的,那么在子元素上不需要重复声明相同的值。较少的样式声明意味着浏览器需要处理的数据量减少,并且还可以降低重绘和回流风险。
利用JavaScript的异步加载
- 异步加载与执行JS:将非关键脚本延迟加载,使用
async
或defer
属性,避免阻塞渲染。 - 事件委托:减少事件监听器的数量,通过委托减少对DOM的操作。
总结
理解渲染引擎与JavaScript引擎的工作原理,以及重绘与回流的机制,我们了解到了想要优化浏览器的性能,就要尽量避免或减少DOM操作次数,选择合适的选择器,尽量少用标签选择器,利用JavaScript的异步加载。