本文提供一个优化网页性能的大概思路, 具体操作网上资料很多
缓存优化
性能优化第一步, 便是管理好页面的缓存, 避免重复下载资源否则, 即增加服务器压力, 又折磨用户的钱包
浏览器缓存机制
访问页面, 请求各种资源, 浏览器检查本地是否有缓存
如果有, 检查资源是否过期没过期, 直接使用缓存过期了, 便向服务器发出请求
发出的请求中会带上 etag 和 last-modified 首部字段
服务器会通过 Etag 和 last-modified 来判断浏览器缓存的资源是否已经不可用
如果资源仍然有效, 便返回 304 告知浏览器使用缓存否则返回更新后的资源
按照这一套逻辑, 便可规划好网站的缓存
如果资源提前过期, 如何通知浏览器更新资源?
通常无法做到这一点, 因为浏览器发现资源没过期, 根本不会发出请求 但是可以通过修改资源的网址来实现所以需要给资源文件名加上版本号或者随机标记例如 style.1234.CSS 也就是说, 不要让浏览器缓存 html 文件, 否则, 过期之前, 浏览器都不会请求服务器
加载时优化
消灭不必要的下载
最好的优化, 便是根本不下载资源所以要尽量减少比不要的资源
评估所有依赖是否必要, 权衡利弊
依赖的下载路径是否可靠, 不可用时候是否会阻碍整个页面
产品设计时候就需要抛弃浪费带宽的设计
压缩所有可以压缩的资源
代码自不用说, 都是文本, 全部压缩
优化图片
去掉不必要的图片
多使用 css3 来代替图片
使用压缩率更高的图片特别是 gif 动图, 一些视频格式 (H.264 或 webM) 的体积比 gif 小很多
用艺术字字体, 不要用图片
仔细权衡图片和文字的关系要表达一个意思, 可能一图胜千言多了一张图片, 反而节省了大量文字
使用 progressive jpeg 相比随着数据下载从上到下显示的 baseline jpeg,progressive jpeg 是由模糊到清晰, 用户体验好, 也不会导致 reflow
图片分辨率要尽可能小, 避免图片分辨率大于显示分辨率
为使用更新浏览器的用户提供更现代的图片格式
多种分辨率的位图供不同页面大小使用
要给标签指明宽高, 否则会导致 reflow
使用 HTTP/2 比如, 精灵图是由很多小图片组成的一张大图片, 可以减少 http 请求但是却难以缓存, 修改一个小图片, 导致所有小图片缓存失效 HTTP/2, 一个链接内可以发起多个请求, 便无需使用精灵图
优化字体
@font-face 中 unicode-range 可以制定字符范围, 用来避免下载不需要的语言的字符
确保字体都被压缩过
用 @font-face 的 display 属性和 FontFace 对象管理好字体加载时的逻辑
关键渲染路径
浏览器渲染一张网页通过以下步骤
处理 HTML 标记并构建 DOM 树
处理 CSS 标记并构建 CSSOM 树
将 DOM 与 CSSOM 合并成一个渲染树
根据渲染树来布局, 以计算每个节点的几何信息
将各个节点绘制到屏幕上
优化关键渲染路径, 便是指优化这个渲染过程, 让网页尽快呈现出来
css
CSS 文件会阻塞渲染浏览器构建好 DOM 树后, 必须等待 CSSOM 树构建完成
在文档顶部防止外联 CSS 的标签, 让浏览器尽快请求 CSS 文件
避免在 css 文件中使用 @import, 因为只有包含 import 的文件被下载编译后, 浏览器才会发现并下载 import 的 css
可以考虑使用内联 CSS, 无需额外请求, 不会阻塞渲染
js
在 CSSOM 构建完成前, js 不会开始执行
js 也会阻止 DOM 树构建除非在 <script > 标签上标记 async
用 Chrome 开发者工具的 audits 检查网页
动画优化
重绘过程
CSS 选择器
选择器越复杂, 浏览器计算得越久最糟情况下, 浏览器需要遍历整个 DOM-tree, 计算量等于元素总个数乘以选择器个数
尽量不要使选择器太复杂, 事先给需要被操作的元素加上类名
reflow, layout
Chrome, Opera, Safari, Internet Explorer 中叫 layout. 火狐称之为 Reflow
reflow, repaint 次数越少越好, 牵连的元素越少越好
reflow 总是牵涉整个文档流
修改元素 css 后立刻读取 css 计算值, 将导致浏览器同步 reflow, 阻塞 js 线程
Paint
浏览器渲染网页时, 会将网页分层(layer), 最后将不同层合并, 然后完成渲染 同一层中, 哪怕只有一个小小的元素发生变化, 整个层都会被 repaint 这一点可以在开发者工具的 Paint Profiler 界面中观察到, layer 界面中可以观察网页有多少个 layer
paint 是耗费性能的
修改 transform 和 opacity 会导致 repaint
创建新 layer 来减少 repaint 区域
will-change 属性可以为元素创建新 layer(works in Chrome, Opera and Firefox). 或 transform: translateZ(0);(works in all browsers).
过多 layer 也消耗内存和性能, 用 Performance 判断新 layer 是否带来优化, 否则不要创建新 layer
高 dpi 屏幕下, fixed 元素自动拥有自己的 layer 低 dpi 需要自行创建
repaint 某个 layer 时, 如果 layer 与其他元素重叠, 将导致 layer 和重叠的元素都被 repaint
最好的动画是跳过 layout 和 paint 直接 composite
用 transform, opacity 来制作动画, 可实现无 layout 和 repaint. (Devtool Performance 的 main 中无动画相关事件)
debounce
debounce: 不要高频率调用函数, 事件连续触发时, 只调用一次函数
交互事件的监听函数的执行时间不能太长, 否则会阻塞页面滚动
不要再交互事件的监听函数中修改样式, 会导致强制同步 reflow, 阻塞 js 执行
debounce, 活用 requestAnimationFrame 方法
监听函数可能会调用 perventDefault, 导致 compositor 线程必须等待监听函数执行完成 不过新扩展的 addEventListener 方法第三个参数可以解决此问题
小技巧
动画不能低于 60 帧 ui 反馈不能低于 100ms
ui 反馈不必追求最快, 可故意拖延到 100ms 并利用这个时间做其他事
尽量增加线程空闲时间, 以快速反馈
ui 反馈优先级最高, 交互期间尽量停下其他任务
来源: http://www.bubuko.com/infodetail-2502841.html