2021.7.19 浏览器渲染机制和CRP优化

CRP:关键渲染路径(critical rendering path)

围绕渲染的机制和步骤,去详细的进行每一步优化,以此来提高页面的渲染速度和运行性能

从服务器基于HTTP网络请求回来的数据

  • 是一串16进制的文件流
  • 浏览器把它解析为字符串(HTML字符串)
  • 按照W3C规则识别为成为一个个的HTML节点[词法解析]
  • 生成xxx树(CSS叫CSSOM树,HTML叫DOM树)

在浏览器中输入一个网址:

  • 首先请求回来的是一个HTML文档,浏览器开始自上而下解析和识别代码(渲染)

  • 接下来渲染页面,此过程中

    • 遇到style内嵌样式,GUI直接渲染即可[同步渲染]

    1.如果CSS代码量比较少,我们直接内嵌即可,拉取HTML的时候,同时CSS也回来了,渲染的时候直接就渲染了
    2.如果CSS代码比较多,如果还用内嵌,一方面会影响HTML的拉取速度,也不利于代码的维护,此时还是用外链的方式比较好

    • 遇到link,浏览器开辟一个HTTP线程去请求资源文件信息,同时GUI继续向下渲染[异步]

    1.浏览器同时能够发送的HTTP请求是有数量限制的(谷歌:5~7个)
    2.超过最大并发限制的HTTP请求需要排队等待
    3.HTTP请求一定是越少越好

    • 遇到@import,浏览器也是开辟HTTP线程去请求资源,但是此时GUI也暂停了(导入式样式会阻碍GUI的渲染),当资源请求回来之后,GUI才能继续[同步渲染]

    真实项目中应该避免使用@import

    • 遇到script标签,会阻碍GUI的渲染(内嵌和外链都一样)
    • 遇到img/音视频等标签,解析顺序和link差不多

对script标签的优化方式

  1. window.addEventListener(‘load’,function(){});
  2. window.addEventListneer(‘DOMContentLoaded’,function(){});
  3. 在script标签中添加一个async属性/defer属性可以避免阻塞
    + defer请求JS资源是异步的[单独开辟HTTP去请求],此时GUI继续渲染,等到GUI渲染完毕,再去渲染JS[不会阻碍GUI渲染]
    + async请求JS资源是异步的[单独开辟HTTP去请求],此时GUI继续渲染,但是一旦JS请求结束,会立即暂停GUI的处理,接下来去渲染JS
    假如我们有5个JS请求,如果不设置任何属性,肯定是按照顺序请求和渲染JS的[依赖关系是有效的]
    但是如果设置了async,谁先请求回来就先渲染谁,依赖关系是无效的;
    如果使用defer是可以建立依赖关系的(浏览器内部在GUI渲染完成后,等待所有设置defer的资源都请求回来,再按照编写的依赖顺序去加载JS)

在真实项目开发中,我们一般把link放在页面的头部[是为了在没有渲染DOM的时候,就通知HTTP去加载CSS了,这样DOM渲染完,CSS也差不多加载好了,更有效的利用事件,提高页面的渲染速度];
我们一般把JS放在页面的底部,防止其阻碍GUI的渲染,如果不放在底部,我们最好设置上async/defer…

页面渲染过程:
首先生成DOM TREE(触发DOMContentLoaded事件)----- [执行JS] ----- 生成CSSOM TREE ----- 生成RENDER TREE渲染树(浏览器未来是按照这个树来绘制页面的)----- Layout布局计算[回流/重排](计算渲染树中各个节点在设备视口内的确切位置和大小)---- Painting绘制[重绘]{分层绘制}{栅格化布局}…

  • 页面第一次渲染,必然会引发一次回流和重绘[很消耗性能:DOM操作消耗性能,90%说的都是它]
  • 如果我们改变了元素的位置和大小,浏览器需要重新计算元素在视口中的位置和大小信息,重新计算的过程是回流/重排,一旦发生了回流操作,一定也会触发重绘
  • 但是如果只是一些普通样式的改变,位置和大小不变,只需要重绘即可

优化方案:

  • 标签语义化和避免深层次嵌套
    • CSS选择器渲染是从右到左,所以写选择器的时候不要写太长,太长会导致CSSOM TREE建立过慢
    • 尽早尽快地把CSS下载到客户端(充分利用HTTP多请求并发机制)

DOM的重绘和回流 Repaint & Reflow

  • 重绘:元素样式的改变(但宽高、大小、位置等不变)

如:outline,visibility,color,background-color等

  • 回流:元素的大小或者位置发生了变化(当页面布局和几何信息发生变化的时候),触发了重新布局,导致渲染树重新计算布局和渲染

如:添加或删除可见的DOM元素;元素的位置发生变化;元素的尺寸发生变化;内容发生变化(比如文本变化或图片被另一个不同尺寸的图片所替代);页面一开始渲染的时候(这个无法避免);因为回流是根据视口大小来计算元素的位置和大小的,所以浏览器的窗口尺寸变化也会引发回流
注意:回流一定引发重绘,而重绘不一定引发回流

前端性能优化之:避免DOM的回流

1.放弃传统操作dom的时代,基于vue/react开始数据影响试图模式

  • mvvm/mvc/virtual dom/dom diff…

2.样式集中改变

xxx.style.cssTest = “” 给行内批量设置样式
xxx.className = xxx 改变其class名称

新版浏览器有一个机制:渲染队列机制
把修改元素样式的操作,依次存放到渲染队列中
(1) 当修改样式的代码已经没有了
(2) 或者遇到了获取元素样式的代码
(3) style.xxx/getComputedStyle/getBoundingClientRect/clientWidth…/offsetWidth…/scrollWidth…
以上三种方式都会刷新渲染队列:把现有队列中的样式去统一修改和渲染,引发一次回流和重绘
由于这个机制,我们可以进行优化:读写分离

3.读写分离:把获取样式和设置样式的操作分离开
offsetTop/offsetLeft/offsetWidth/offsetHeight/clientTop/clientLeft/clientWidth/clientHeight/scrollTop/scrollLeft/scrollWidth/scrollHeight/getComputedStyle/currentStyle…会刷新渲染队列

4.缓存布局信息

5.元素批量修改 createDocumentFragment()
文档碎片:

let box = document.querySelector('#box');
	frag = document.createDocumentFragment();
for(let i = 0; i < 10; i++) {
	let span = document.createElement('span');
	span.innerHTML = i + 1;
	frag.appendChild(span);
}
box.appendChild(frag);

除了这种方式,还可以用模板字符串拼接的形式进行添加新元素

6.动画效果应用到position属性为absolute或fixed的元素上(脱离文档流) CSS是分层渲染的,改变单独层级会比改变整体文档流好

7.CSS3硬件加速(GPU加速)

  • 比起考虑如何减少回流重绘,我们更期望的是,根本不要回流重绘;transform/opacity/filters…这些属性会触发硬件加速,不会引发回流和重绘

8.牺牲平滑度换取速度

  • 每次1像素移动一个动画,但是如果此动画使用了100%的CPU,动画就会看上去是跳动的,因为浏览器正在与更新回流作斗争,每次移动3像素可能看起来平滑度低了,但它不会导致CPU在较慢的机器中抖动

9.避免table布局和使用css的javascript表达式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值