前端性能优化-浏览器运行机制

解锁浏览器背后的运行机制

浏览器的"心"

之所以不同的浏览器下代码渲染结果有差异 正是因为浏览器的内核不一致导致的 , 浏览器的内核决定了浏览器解释网页语法的方式.

浏览器内核可以分为两部分 渲染引擎 和 js引擎

渲染引擎包含了 HTML解释器 , css 解释器 , 布局 , 网络 , 存储 , 图形 , 音视频 , 图片解码器等零件

开启浏览器渲染"黑盒"

Q : 什么是渲染过程 ? A : 简单的说 渲染引擎根据 html 文件描述 将资源转换为图像结果

其中比较重要的部分是

  • HTML 解释器 : 将 html 文档经过词法分析输出 DOM 树
  • CSS 解释器 : 解析 css 文档 , 生成样式规则
  • 图层布局计算模块 : 布局计算每个对象的精确位置和大小
  • 视图绘制模块 : 进行具体的图像绘制 , 将像素渲染到屏幕上
  • javascript 引擎 : 编译 执行 js 代码

浏览器渲染过程解析

  • 解析 HTML 在这一步浏览器执行了所有的加载解析逻辑,在解析 HTML 的过程中发出了页面渲染所需的各种外部资源请求。

  • 计算样式 浏览器将识别并加载所有的 CSS 样式信息与 DOM 树合并,最终生成页面 render 树(:after :before 这样的伪元素会在这个环节被构建到 DOM 树中)。

  • 计算图层布局 页面中所有元素的相对位置信息,大小等信息均在这一步得到计算。

  • 绘制图层 在这一步中浏览器会根据我们的 DOM 代码结果,把每一个页面图层转换为像素,并对所有的媒体文件进行解码。

  • 整合图层,得到页面 最后一步浏览器会合并合各个图层,将数据由 CPU 输出给 GPU 最终绘制在屏幕上。(复杂的视图层会给这个阶段的 GPU 计算带来一些压力,在实际应用中为了优化动画性能,我们有时会手动区分不同的图层)。

几棵重要的"树"

  • DOM 树: 解析 HTML 以创建的是 DOM 树(DOM tree ):渲染引擎开始解析 HTML 文档,转换树中的标签到 DOM 节点,它被称为"内容树"。

  • CSSOM 树: 解析 CSS(包括外部 CSS 文件和样式元素)创建的是 CSSOM 树。CSSOM 的解析过程与 DOM 的解析过程是并行的。

  • 渲染树: CSSOM 与 DOM 结合,之后我们得到的就是渲染树(Render tree )。

  • 布局渲染树: 从根节点递归调用,计算每一个元素的大小、位置等,给每个节点所应该出现在屏幕上的精确坐标,我们便得到了基于渲染树的布局渲染树(Layout of the render tree)。

  • 绘制渲染树: 遍历渲染树,每个节点将使用 UI 后端层来绘制。整个过程叫做绘制渲染树(Painting the render tree)。

渲染过程: 首先是基于 HTML 构建一个 DOM 树,这棵 DOM 树与 CSS 解释器解析出的 CSSOM 相结合,就有了布局渲染树。最后浏览器以布局渲染树为蓝本,去计算布局并绘制图像

之后每当一个新元素加入到这个 DOM 树当中,浏览器便会通过 CSS 引擎查遍 CSS 样式表,找到符合该元素的样式规则应用到这个元素上,然后再重新去绘制它。

css 优化建议

css 复制代码
#myList li {
  /*  */
}

CSS 选择符是从右到左进行匹配的。这个选择器实际开销相当高:浏览器必须遍历页面上每个 li 元素,并且每次都要去确认这个 li 元素的父元素 id 是不是 myList

通配符也是个消耗性能的选择器 , 因为他会遍历页面上的每一个元素

告别阻塞: css 与 js 的加载顺序优化

html css js 都具有阻塞渲染的特性

css 阻塞

因为 DOM Tree + CSSOM = Render Tree 所以只要 css 没加载完 就不会往后走渲染流程

由于 html 解析到 <link /> 和 <style />标签的时候 CSSOM 才开始构建 . 所以可以尽可能把构建时机提前.

比如 :

  • 放在 <head /> 里 (尽早)
  • 启用 CDN (尽快)

js 阻塞

js 的作用在于 修改节点 , 本质上都是对 DOM 和 CSSOM 进行修改 , 所以 JS 的执行会阻塞

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>JS阻塞测试</title>
    <style>
      #container {
        background-color: yellow;
        width: 100px;
        height: 100px;
      }
    </style>
    <script>
      // 尝试获取container元素
      var container = document.getElementById("container");
      console.log("container", container);
    </script>
  </head>
  <body>
    <div id="container"></div>
    <script>
      // 尝试获取container元素
      var container = document.getElementById("container");
      console.log("container", container);
      // 输出container元素此刻的背景色
      console.log(
        "container bgColor",
        getComputedStyle(container).backgroundColor
      );
    </script>
    <style>
      #container {
        background-color: blue;
      }
    </style>
  </body>
</html>

运行结果是

javscript 复制代码
container null
index.html:26 container <div id=​"container">​</div>​
index.html:28 container bgColor rgb(255, 255, 0)
index.html:63 Live reload enabled.

JS 是外部文件的时候 表现也是这样的

第一次获取 DOM 失败 说明 js 阻塞了 DOMTree 的生成 第二次获取 DOM 成功 (预期内) 但是获取 css 拿到的是 yellow 的颜色 而不是后续配置的 blue 证明 CSSOM 也被阻塞了

js 的加载方式

  • 正常模式

这种模式下会阻塞

javascript 复制代码
<script src="./index.js" />
  • async 模式

async 模式下,JS 不会阻塞浏览器做任何其它的事情。它的加载是异步的,当它加载结束,JS 脚本会立即执行。

javascript 复制代码
<script async src="./index.js" />
  • defer 模式

defer 模式下,JS 的加载是异步的,执行是被推迟的。等整个文档解析完成、DOMContentLoaded 事件即将被触发时,被标记了 defer 的 JS 文件才会开始依次执行。

javascript 复制代码
<script defer src="./index.js" />
相关推荐
小远yyds18 分钟前
前端Web用户 token 持久化
开发语言·前端·javascript·vue.js
阿伟来咯~1 小时前
记录学习react的一些内容
javascript·学习·react.js
吕彬-前端1 小时前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱1 小时前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai1 小时前
uniapp
前端·javascript·vue.js·uni-app
也无晴也无风雨1 小时前
在JS中, 0 == [0] 吗
开发语言·javascript
bysking2 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓3 小时前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_4113 小时前
无网络安装ionic和运行
前端·npm
理想不理想v3 小时前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试