从解析HTML开始,破解页面渲染时间长难题
摘要:在本文中,将重点关注网页的初始渲染,即它从解析 HTML 开始。 我将探索可能导致高渲染时间的问题,以及如何解决它们。
本文分享自华为云社区《页面首屏渲染性能指南》,作者:Ocean2022。
我们知道渲染页面是一个将服务器的响应内容翻译成图片的过程。但是,如果你页面的渲染性能比较糟糕的话,可能会带来相对较高的跳出率。
在本文中,我将重点关注网页的初始渲染,即它从解析 HTML 开始。 我将探索可能导致高渲染时间的问题,以及如何解决它们。
关键渲染路径(CRP)
关键渲染路径 (CRP) 是浏览器将代码转换为屏幕上可显示像素的过程。 它有几个阶段,其中一些可以并行执行以节省时间,但有些部分必须依次完成。 如下图所示:

首先,一旦浏览器得到响应,它就会开始解析它。 当它遇到依赖项时,它会尝试下载它。 如果它是一个样式表文件,浏览器必须在渲染页面之前完全解析它,这就是为什么 CSS 会阻塞渲染的原因。
如果是脚本,浏览器必须:停止解析,下载脚本,然后运行。 只有在那之后它才能继续解析,因为 JavaScript 程序可以改变网页的内容(尤其是 HTML)。 这就是为什么 JS 会阻塞解析的原因。
完成所有解析后,浏览器将构建文档对象模型 (DOM) 和级联样式表对象模型 (CSSOM)。 将它们组合在一起得到渲染树。 页面的不显示部分不会进入渲染树,因为它只包含绘制页面所需的数据。
倒数第二步是将渲染树进行布局, 这个阶段也称为回流:就是计算每个渲染树节点的每个位置及其大小的地方。
最后一步是绘制。 它会根据浏览器在前一阶段计算得到的数据对像素进行着色。
优化相关结论
因此,根据这一过程,我们在优化性能方面,得出了一些结论。如果你要提升页面初始化渲染的性能,你需要:
- 减少传输的数据量
- 减少浏览器必须下载的资源数量(尤其是阻塞的资源)
- 减小 CRP 的长度
同时,我们会根据下面 3 个指标来衡量优化的效率:
- FP(First Paint)
- FCP(First Contentful Paint)
- FMP(First Meaningful Paint)
除了渲染时间之外,还有其他一些因素也需要考虑。例如,你的页面使用了多少阻塞资源以及下载它们需要多长时间。
性能优化策略
鉴于我们在上面得出的结论,我们得出网站性能优化有三种主要策略:
- 尽量减少通过网络传输的数据量;
- 减少通过网络传输的资源总数;
- 缩短关键渲染路径;
1. 减少要传输的数据量
首先,移除所有未使用的部分,例如 JavaScript 中无法访问的函数、带有从不匹配任何元素的选择器的样式以及被 CSS 永远隐藏的 HTML 标签。 其次,删除所有重复项。
然后,我建议建立一个自动压缩过程。 例如,它应该从你的后端服务中删除所有注释(但不是源代码)以及每个不包含附加信息的字符(例如 JS 中的空白字符)。
完成后,我们剩下的可以是文本字符串。 这意味着我们可以安全地应用诸如 GZIP(大多数浏览器都理解)之类的压缩算法。
最后,还有缓存。 浏览器第一次呈现页面时它不会有帮助,但它会在以后的访问中节省很多。 但是,记住两点至关重要:
- 如果你使用 CDN,请确保支持缓存并在正确设置。
- 与其等待资源的到期,不如 将文件的“指纹”嵌入到其 URL 中,以使本地缓存无效。
当然,应该为每个资源定义缓存策略。 有些可能很少改变或根本不会改变,有的则是变化的很快,还有些文件包含敏感的信息(可以使用 “private” 防止 CDN 缓存私有数据)。
2. 减少关键资源的总数
“关键”仅指网页正确呈现所需的资源。 因此,我们可以直接跳过所有流程中没有涉及的样式以及脚本文件。
样式
为了告诉浏览器不需要特定的 CSS 文件,我们应该为所有引用样式表的链接设置媒体属性。 使用这种方法,浏览器将只根据需要处理与当前媒体(设备类型、屏幕尺寸)匹配的资源,同时降低所有其他样式表的优先级。 例如,如果你将 media=“print” 属性添加到引用样式以打印页面的样式标记,则这些样式不会在不打印媒体时干扰你的关键渲染路径。
为了进一步改进该过程,你还可以将一些样式内联,这可以为我们节省了至少一次到服务器的往返行程。
脚本
如上所述,脚本会阻塞解析,因为它们可以改变 DOM 和 CSSOM。 为了避免这一点,所有脚本标签都必须用属性标记——异步或延迟。
标有 async 的脚本不会阻塞 DOM 构建或 CSSOM,因为它们可以在 CSSOM 构建之前执行。 但请记住,内联脚本无论如何都会阻止 CSSOM,除非你将它们放在 CSS 之上。相比之下,标有 defer 的脚本将在页面加载结束时进行执行。
换句话说,使用 defer,脚本直到页面加载事件被触发后才会执行,而 async 让脚本在文档被解析时就会在后台运行。
3.缩短关键渲染路径长度
最后,应将 CRP 长度缩短到可能的最小值。
作为样式标签属性的媒体查询将减少必须下载的资源总数。 script 标签属性 defer 和 async 将防止相应的脚本阻塞解析。
使用 GZIP 压缩、压缩和归档资源将减少传输数据的大小(从而也减少数据传输时间)。
内联一些样式和脚本也可以减少浏览器和服务器之间的往返次数。
按照最新的最佳性能实践理念,一个网站应该做的最快的第一件事就是展示 ATF 内容。 ATF 代表首屏。 这是立即可见的区域,无需滚动。 因此,最好以首先加载所需样式和脚本的方式重新排列与渲染相关的所有内容,而其他所有内容都停止(既不解析也不渲染)。
结尾
总而言之,网站性能优化包含了网站响应的各个方面,例如缓存、设置 CDN、重构、资源优化等,但是所有这些都可以逐步完成。 作为 Web 开发人员,你可以将本文作为参考,并始终记住在实验之前和之后测量性能。
浏览器开发人员尽最大努力优化你访问的每个页面的网站性能,这就是浏览器通常实现所谓的“预加载器”的原因。 这部分程序会在你以 HTML 格式请求的资源之前进行扫描,以便一次发出多个请求并让它们并行运行。 这就是为什么在 HTML(逐行)以及脚本标签中保持样式标签彼此靠近的原因。
此外,尝试批量更新 HTML 以避免多个布局事件,这些事件不仅由 DOM 或 CSSOM 中的更改触发,而且在设备方向更改和窗口大小调整时也会触发。
从解析HTML开始,破解页面渲染时间长难题的更多相关文章
- 加载 CSS 时不影响页面渲染
转自:http://www.oschina.net/translate/loading-css-without-blocking-render 本文展示了一种技术,它能通过异步下载样式表,以阻止它们的 ...
- 多进程浏览器、多线程页面渲染与js的单线程
线程与进程 说到单线程,就得从操作系统进程开始说起.在早期的操作系统中并没有线程的概念,进程是能拥有资源和独立运行的最小单位,也是程序执行的最小单位.任务调度采用的是时间片轮转的抢占式调度方式,而进程 ...
- 《Webkit技术内幕》之页面渲染过程
文章同步到github<Webkit技术内幕>之页面渲染过程 最近拜读了传说中的<Webkit技术内幕>一书,有很大收获,尤其是对页面渲染有了较深的认识.由于功力有限,而且书中 ...
- 一文摸透从输入URL到页面渲染的过程
一文摸透从输入URL到页面渲染的过程 从输入URL到页面渲染需要Chrome浏览器的多个进程配合,所以我们先来谈谈现阶段Chrome浏览器的多进程架构. 一.Chrome架构 目前Chrome采用的是 ...
- 【前端性能】高性能滚动 scroll 及页面渲染优化
最近在研究页面渲染及web动画的性能问题,以及拜读<CSS SECRET>(CSS揭秘)这本大作. 本文主要想谈谈页面优化之滚动优化. 主要内容包括了为何需要优化滚动事件,滚动与页面渲染的 ...
- 【前端性能】高性能滚动 scroll 及页面渲染优化--转发
本文主要想谈谈页面优化之滚动优化. 主要内容包括了为何需要优化滚动事件,滚动与页面渲染的关系,节流与防抖,pointer-events:none 优化滚动.因为本文涉及了很多很多基础,可以对照上面的知 ...
- 高性能滚动 scroll 及页面渲染优化
最近在研究页面渲染及web动画的性能问题,以及拜读<CSS SECRET>(CSS揭秘)这本大作. 本文主要想谈谈页面优化之滚动优化. 主要内容包括了为何需要优化滚动事件,滚动与页面渲染的 ...
- 前端高性能滚动 scroll 及页面渲染优化
前言 最近在研究页面渲染及web动画的性能问题,以及拜读<CSS SECRET>(CSS揭秘)这本大作.本文主要想谈谈页面优化之滚动优化. 主要内容包括了为何需要优化滚动事件,滚动与页面渲 ...
- JS学习笔记:(一)浏览器页面渲染机制
浏览器的内核主要分为渲染引擎和JS引擎.目前市面上常见的浏览器内核可以分为这四种:Trident(IE).Gecko(火狐).Blink(Chrome.Opera).Webkit(Safari).这里 ...
随机推荐
- gnome shell 扩展命令行开启和关闭
#关闭 gnome-shell-extension-tool -d 扩展名 #开启 gnome-shell-extension-tool -e 扩展名 例如: gnome-shell-extensio ...
- 【面试普通人VS高手系列】Dubbo的服务请求失败怎么处理?
今天分享的面试题,几乎是90%以上的互联网公司都会问到的问题. "Dubbo的服务请求失败怎么处理"? 对于这个问题,我们来看一下普通人和高手的回答. 普通人: 嗯- 我记得, D ...
- Kernel pwn 基础教程之 Heap Overflow
一.前言 在如今的CTF比赛大环境下,掌握glibc堆内存分配已经成为了大家的必修课程.然而在内核态中,堆内存的分配策略发生了变化.笔者会在介绍内核堆利用方式之前先简单的介绍一下自己了解的内核内存分配 ...
- Spring从入门到源码(一)
Spring 1.什么是框架? 人话就是:方便干活,架子有了,直接拿来用就完事了. spring,springmvc,mybatis三大开框架 2.架构的演变过程 单一应用架构 垂直应用架构 分布式服 ...
- Java基础语法Day_02-03(数据类型、运算符、方法、循环结构)
第5节 数据类型转换 day02_01_数据类型转换_自动转换 day02_02_数据类型转换_强制转换 day02_03_数据类型转换_注意事项 day02_04_ASCII编码表 第6节 运算符 ...
- 《Streaming Systems》第一章: Streaming 101
数据的价值在其产生之后,将随着时间的流逝逐渐降低.因此,为了获得最大化的数据价值,尽可能实时.快速地处理新产生的数据就显得尤为重要.实时数据处理将在越来越多的场景中体现出更大的价值所在 -- 实时即未 ...
- lab_0 清华大学ucore实验环境配置详细步骤!(小白入)
实验步骤 1.下载项目 从github上 的https://github.com/kiukotsu/ucore下载 ucore lab实验: git clone https://github.com/ ...
- 为什么列式存储会被广泛用在 OLAP 中?
大家好,我是大D. 不知是否有小伙伴们疑问,为什么列式存储会广泛地应用在 OLAP 领域,和行式存储相比,它的优势在哪里?今天我们一起来对比下这两种存储方式的差别. 其实,列式存储并不是一项新技术,最 ...
- 基于.NetCore开发博客项目 StarBlog - (6) 页面开发之博客文章列表
系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...
- uni-simple-router
目录 uni-simple-router 一.快速上手 扩一:webpack插件之DefinePlugin 扩二:uni-read-pages 如何获取pages.json中的路由 二.H5模式 2. ...