通过了解浏览器的底层,理清究竟是什么影响了网页的性能?

292 阅读5分钟

前言

在构建高效、流畅的网页应用时,了解浏览器的渲染流程及其背后的引擎工作原理至关重要。今天我们将深入探讨渲染引擎与JavaScript引擎的运行机制,以及它们是如何影响页面性能的,该怎样来优化我们的性能

浏览器的内核

浏览器内核主要由渲染引擎和JavaScript引擎这两大部分组成,它们共同决定了浏览器如何处理和展示网页内容,以及如何响应用户与网页的交互。

渲染引擎:从代码到视觉的桥梁

渲染引擎负责将HTML、CSS和JavaScript转换为用户可见的图像。其工作流程大致分为以下几个步骤:

  1. 解析HTML:通过DOM解析器将HTML文档转换为可操作的对象模型——DOM树。
  2. 解析CSS:CSS解析器将CSS代码转换为CSS对象模型(CSSOM)树,描述了文档的样式信息。
  3. 生成渲染树:结合DOM树与CSSOM树,生成渲染树(Render Tree),只包含需渲染的元素及相应样式。
  4. 布局(Layout) :计算渲染树中每个节点的确切位置和尺寸,形成布局树(Layout Tree)。
  5. 绘制(Paint) :将布局树的各个节点绘制到屏幕上,这一过程可能涉及硬件加速,即由CPU调度GPU完成。
  6. 合成(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:将非关键脚本延迟加载,使用asyncdefer属性,避免阻塞渲染。
  • 事件委托:减少事件监听器的数量,通过委托减少对DOM的操作。

总结

理解渲染引擎与JavaScript引擎的工作原理,以及重绘与回流的机制,我们了解到了想要优化浏览器的性能,就要尽量避免或减少DOM操作次数,选择合适的选择器,尽量少用标签选择器,利用JavaScript的异步加载。