本文会通过三部分来介绍web性能相关
- 为什么web性能重要
- 怎么测试web性能
- 怎么改善性能
1 Why does speed matter
这部分我不是很想说,就像在搜集证据说钱多么重要一样,但还是应付的给个参考链接:Why does speed matter?。
比如性能关乎用户体验,进一步影响用户留存、转化率。
2 How to measure speed
评测一个web应用包含很多指标,比如RAIL model对response, animation, idle, and load四个方面进行了评估。
另外推荐一些常用的测试工具,比如Chrome DevTools,WebPageTest,lighthouse。
其中WebPageTest是一个在线的测试网站,可以对指定域名生成测评报告,结果如下
lighthouse可用chrome自带版本,也可以使用lighthouse-cli,结果如下
带有--locale=zh-cn
参数可以指定中文报告,打分指标参考这里。
PageSpeed Insights也使用了lighthouse的数据。
3 How to improve performance
这部分我打算分两个部分介绍
- 内容加载
- 内容渲染
3.1 内容加载
这部分介绍页面怎么减少内容加载对网站性能的影响,可以分为以下思路,即一个页面的加载,从请求、传输、下载以及其他细节方面来考虑
3.1.1 减少请求次数
- 利用ssr,加快首屏渲染,有利于seo
- http2的server push,也能加快首屏渲染,但和seo没关
- 用css样式代替图片或雪碧图或者base64表示图片
- 代码打包合并
- 本地存储
3.1.2 减少下载次数
- 使用http缓存
3.1.3 减少下载总量
- 压缩资源,包括代码和图片等,包括打包时的压缩和http压缩
- 少使用第三方library
- tree shaking
- 将部分第三方包由runtime提供,比如webpack的externals,多用于library开发
3.1.4 减少网络传播时间
- cdn
- http/2
- 减少header payload
3.1.5 其他
- 代码拆分
- 懒加载,比如script的defer或async属性或者按需加载
- 预处理,link标签的rel属性相关的优化,包括
- dns-prefetch 提前解析dns
- preconnect 提前建立连接(包括dns查询、tcp连接和tls协商)
- prefetch 下次导航时可能需要,应该提前获取
- prerender 下个导航可能需要,应该提前执行,比如渲染一个html
- preload 相对于prefetch优先级高,且是当前导航中需要的资源
3.2 内容渲染
本部分会结合页面的渲染中的五个步骤,对其进行优化,还会参考Rendering Performance。
大部分设备屏幕刷新率为60fps,这样渲染时的每一帧需要16ms的准备时间,每一帧期间除渲染本身以外的其他工作只有10ms,如果超过这个时间就会掉帧,这被称作 jank。
3.2.1 parse
渲染的第一步本是解析html,这里代指所有会引起页面渲染的操作,比如动画、过渡、scroll或其他交互。
-
首次渲染,首次渲染时诸多因素与内容加载有关系,注意遇到script会阻塞页面解析,css随不会阻塞,但是页面要等cssom解析完成才能下一步操作,具体参考关键路径优化。
-
使用window.requestAnimationFrame()可以在帧开始执行画面修改,而不是其他timer,因为后者可能发生在帧的结尾时刻,导致丢帧。
-
对于长时间的工作,如果是纯计算等可以使用web worker完成的就开一个worker线程,否则对于优先级高的任务可以使用window.requestAnimationFrame(),优先级低的使用window.requestIdleCallback()将复杂计算转换成多个小计算来进行。
-
少操作dom,dom操作本身就很消耗性能
3.2.2 Style calculation
样式计算分为两个步骤
- 计算出哪些元素应用当前样式,这一步可以通过降低选择器复杂度来解决,比如使用BEM命名规范,具体选择器解析顺序是从右到左,创建选择器时应加以注意。
- 将样式匹配到对应的元素上,这一步可以通过减少要计算样式的元素数量解决。
3.2.3 layout
layout是计算各需要显示元素的坐标
- 选用不影响元素坐标的动画或过渡,包括 transforms or opacity
- 使用flexBox而不是旧的模型,后者盒子多
- 避免forced synchronous layout造成的卡顿或layout thrashing。一个页面包含两个tree,其中一个表示实际的dom,一个表示内存中被js操作的dom,操作前者很耗费性能,当读取元素样式时会强制元素渲染,即修改实际dom,在执行一系列dom操作时应避免这种情况,比如
function resizeAllParagraphsToMatchBlockWidth() {
// Puts the browser into a read-write-read-write cycle.
for (var i = 0; i < paragraphs.length; i++) {
paragraphs[i].style.width = box.offsetWidth + 'px';
}
}
应修改为
// Read.
var width = box.offsetWidth;
function resizeAllParagraphsToMatchBlockWidth() {
for (var i = 0; i < paragraphs.length; i++) {
// Now write.
paragraphs[i].style.width = width + 'px';
}
}
- 使用DocumentFragment组织连续dom的插入,参考Document Fragments and why you should use them,如果单独插入,每次插入都是一个宏任务,都会引起页面渲染,如果用该方法可以减少渲染次数。
3.2.4 paint
这里计算绘制顺序,layout后就会paint,这一步没有特别的优化步骤
3.2.5 compositing
这一步将前面获取的信息分层并分别栅格化
- 利用willchange或transform: translateZ(0)将需要改动的元素分到单独的层,主要分层本身就消耗性能,不要对过多元素使用
- 降低动画复杂度,那些涉及模糊的消耗性能更多,比如
background: red;
和box-shadow: 0, 4px, 4px, rgba(0,0,0,0.5);
相比 - 对于标记为Non-Fast Scrollable Region的区域,即有事件绑定的区域,如果存在交互,会触发main线程处理,可以在事件监听器使用
passive: true
解决,具体参考这里。 - throttle和debounce
完结撒花
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!