1. 重排优化
减少重排范围
-
尽可能在低层级的DOM节点上,而不是像上述全局范围的示例代码一样,如果你要改变p的样式,class就不要加在div上,通过父元素去影响子元素不好。
-
不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局。那么在不得已使用table的场合,可以设置table-layout:auto;或者是table-layout:fixed这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围。
减少重排次数
-
1.样式集中改变
- 不要频繁的操作样式,对于一个静态页面来说,明智且可维护的做法是更改类名而不是修改样式,对于动态改变的样式来说,相较每次微小修改都直接触及元素,更好的办法是统一在 cssText 变量中编辑。
-
2.分离读写操作
- DOM 的多个读操作(或多个写操作),应该放在一起。不要两个读操作之间,加入一个写操作。
-
3.将 DOM 离线
- 使用 display:none(后面再显示,总共触发两次重排)
- 通过 documentFragment 创建一个 dom 碎片,在它上面批量操作 dom,操作完成之后,再添加到文档中,这样只会触发一次重排。
- 复制节点,在副本上工作,然后替换它!
-
4.使用 absolute 或 fixed 脱离文档流
-
5.优化动画
- 可以把动画效果应用到 position属性为 absolute 或 fixed 的元素上,这样对其他元素影响较小。
- 启用GPU加速 GPU 硬件加速是指应用 GPU 的图形性能对浏览器中的一些图形操作交给 GPU 来完成,因为 GPU 是专门为处理图形而设计,所以它在速度和能耗上更有效率。
- GPU 加速通常包括以下几个部分:Canvas2D,布局合成, CSS3转换(transitions),CSS3 3D变换(transforms),WebGL和视频(video)。
/* * 根据上面的结论 * 将 2d transform 换成 3d * 就可以强制开启 GPU 加速 * 提高动画性能 */ div { transform: translate3d(10px, 10px, 0); } 复制代码
2.白屏优化
1. DNS解析优化
针对DNS Lookup环节,我们可以针对性的进行DNS解析优化。
- DNS缓存优化
- 减少DNS查询次数。 减少DNS查询次数需要减少来自不同domain的请求的数量,如尽量将外部域的对象下载到本地服务器上等。
- DNS预加载策略
- 可以通过用meta信息来告知浏览器, 我这页面要做DNS预解析
<meta http-equiv="x-dns-prefetch-control" content="on" /> 复制代码
- 可以使用link标签来强制对DNS做预解析:
<link rel="dns-prefetch" href="http://ke.qq.com/" /> 复制代码
- 稳定可靠的DNS服务器
2. TCP网络链路优化
针对网络链路的优化,好像除了花钱没有什么更好的方式!
3. 服务端处理优化
服务端的处理优化,是一个非常庞大的话题,会涉及到如Redis缓存、数据库存储优化或是系统内的各种中间件以及Gzip压缩等…
4. 浏览器下载、解析、渲染页面优化
根据浏览器对页面的下载、解析、渲染过程,可以考虑一下的优化处理:
- 尽可能的精简HTML的代码和结构
- 尽可能的优化CSS文件和结构
- 一定要合理的放置JS代码,尽量不要使用内联的JS代码
3.大量图片加载优化
1. 浏览器有连接请求限制,一般浏览器都是最大http连接数被限制在6个,有以下解决方法
-
- 懒加载,没有浏览到的图片暂不请求
- 判断图片是否是首屏内图片,首先想到的肯定是通过 getBoundingClientRect 方法,获取到图片的位置信息,判断其是否在 viewport 内部。
const inViewport = (el) => { const rect = el.getBoundingClientRect() return rect.top > 0 && rect.bottom < window.innerHeight && rect.left > 0 && rect.right < window.innerWidth } 复制代码
- 懒加载,没有浏览到的图片暂不请求
-
- 小图片比较多,可以用雪碧图、字体图标、base64等,这样可以有效减少连接数
-
- 在 HTTP/1.0 和 HTTP/1.1 协议下,由于 Chrome 只支持同域同时发送 6 个并发请求,可以进行域名切分,来提升并发的请求数量.
-
- 连接数限制问题还可以由http2来解决,http2一个站点只有一个连接。每个请求为一个流,每个请求被分为多个二进制帧,不同流中的帧可以交错的发送,实现多路复用。这就解决了连接数限制的问题
2、图片过大,传输和渲染比较慢,有以下的处理办法
-
- 如果是相册之类的可以预加载,在展示当前图片的时候,就加载它的前一个和后一个图片
-
- 加载的时候可以先加载一个压缩率非常高的缩略图,以提高用户体验
-
- 使用渐进式jpeg,会提高用户体验
-
- 如果展示区域小于图片的真实大小,可以在服务端先压缩到合适的尺寸
4. 浏览器从输入网址到页面展现的整个过程
- 1,用户输入url并回车
- 2,浏览器进程检查url,组装协议,构成完整的url
- 3,浏览器进程通过进程间通信(IPC)把url请求发送给网络进程
- 4,网络进程接收到url请求后检查本地缓存是否缓存了该请求资源,如果有则将该资源返回给浏览器进程
- 5,如果没有,网络进程向web服务器发起http请求(网络请求),请求流程如下:
- 5.1 进行DNS解析,获取服务器ip地址,端口(端口是通过dns解析获取的吗?这里有个疑问)
- 5.2 利用ip地址和服务器建立tcp连接
- 5.3 构建请求头信息
- 5.4 发送请求头信息
- 5.5 服务器响应后,网络进程接收响应头和响应信息,并解析响应内容
- 6,网络进程解析响应流程;
-
6.1 检查状态码,如果是301/302,则需要重定向,从Location自动中读取地址,重新进行第4步,如果是200,则继续处理请求。
-
6.2 200响应处理:
检查响应类型Content-Type,如果是字节流类型,则将该请求提交给下载管理器,该导航流程结束,不再进行
后续的渲染,如果是html则通知浏览器进程准备渲染进程准备进行渲染。
-
- 7,准备渲染进程
- 7.1 浏览器进程检查当前url是否和之前打开的渲染进程根域名是否相同,如果相同,则复用原来的进程,如果不同,则开启新的渲染进程
-
- 传输数据、更新状态
- 8.1 渲染进程准备好后,浏览器向渲染进程发起“提交文档”的消息,渲染进程接收到消息和网络进程建立传输数据的“管道”
- 8.2 渲染进程接收完数据后,向浏览器发送“确认提交”
- 8.3 浏览器进程接收到确认消息后更新浏览器界面状态:安全、地址栏url、前进后退的历史状态、更新web页面。
-
- 渲染流水线
- 构建 DOM 树
-
- 输入:HTML 文档;
-
- 处理:HTML 解析器解析;
-
- 输出:DOM 数据解构。
-
- 样式计算
-
- 输入:CSS 文本;
-
- 处理:属性值标准化,每个节点具体样式(继承、层叠);
-
- 输出:styleSheets(CSSOM)。
-
- 布局(DOM 树中元素的计划位置)
-
- DOM & CSSOM 合并成渲染树;
-
- 布局树(DOM 树中的可见元素);
-
- 布局计算。
-
- 分层
-
- 特定节点生成专用图层,生成一棵图层树(层叠上下文、Clip,类似 PhotoShop 里的图层);
-
- 拥有层叠上下文属性(明确定位属性、透明属性、CSS 滤镜、z-index 等)的元素会创建单独图层;
-
- 没有图层的 DOM 节点属于父节点图层;
-
- 需要剪裁的地方也会创建图层。
-
- 绘制指令
-
- 输入:图层树;
-
- 渲染引擎对图层树中每个图层进行绘制;
-
- 拆分成绘制指令,生成绘制列表,提交到合成线程;
-
- 输出:绘制列表。
-
- 分块
-
- 合成线程会将较大、较长的图层(一屏显示不完,大部分不在视口内)划分为图块(tile, 256256, 512512)。
-
- 光栅化(栅格化)
-
- 在光栅化线程池中,将视口附近的图块优先生成位图(栅格化执行该操作);
-
- 快速栅格化:GPU 加速,生成位图(GPU 进程)。
-
- 合成绘制
-
- 绘制图块命令——DrawQuad,提交给浏览器进程;
-
- 浏览器进程的 viz 组件,根据DrawQuad命令,绘制在屏幕上。
-
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END