《现代前端技术解析》第5章阅读笔记(三)
- 笔记章节目录
- 2020/02/22
5.4 前端性能优化
- 前端性能: 通常前端性能可以认为是用户获取所需要页面数据或执行某个页面动作的一个实时性指标,一般以用户希望获取数据的操作到用户实际获取的数据的时间间隔来衡量。
5.4.1 前端性能测试
-
Performance Timing API: *(IE9+、WebKit)*用于记录页面加载和解析过程中关键时间点的机制,它可以详细记录每个页面资源从开始加载到完成这一过程中具体操作发生的时间点。但是无法统计JS执行过程中系统资源的占用情况。(p248 - 250)
-
浏览器加载和解析HTML的过程: unload, redirect, App Cache, DNS, TCP, Request, Processing, onload.
-
Performance Timing 关键时间点记录:
let timing = performance.timing, readyStart = timing.fetchStart - timing.navigationStart, //准备新页面时间耗时 redirectTime = timing.redirectEnd - timing.redirectStart, //redirect重定向耗时 appCacheTime = timing.domainLookupStart - timing.fetchStart, //App Cache耗时 unloadEventTime = timing.unloadEventEnd - timing.unloadEventStart, //unload前文档耗时 lookupDomainTime = timing.domainLookupEnd - timing.domainLookupStart, //DNS查询耗时 connectTime = timing.connectEnd - timing.connectStart, //TCP连接耗时 requestTime = timing.responseEnd - timing.requestStart, //request请求耗时 initDomTreeTime = timing.domInteractive - timing.responseEnd, //请求完毕至DOM加载好耗时 domReadyTime = timing.domComplete - timing.domInteractive, //解析DOM树耗时 loadEventTime = timing.loadEventEnd - timing.loadEventStart, //load事件耗时 loadTime = timing.loadEventEnd - timing.navigationStart; //加载时间耗时
对前端有意义的几个过程主要是解析DOM树耗时(
domReadyTime
)、load事件耗时(loadEventTime
)和整个加载过程耗时(loadTime
)等。 -
performance的其他功能:
performance.memory //内存占用的具体数据 performance.navigation //用户行为信息,例如网络请求类型和重定向次数等 performance.navigation.redirectCount //当前网页的重定向跳转的次数
-
-
Profile工具: 是Chrome和Firefox等标准浏览器提供的一种用于测试页面脚本运行时系统内存和CPU资源占用情况的API。(p250)
eg: chrome可以实现的几个功能:
- 分析页面脚本执行过程中最耗资源的操作;
- 记录页面脚本执行过程中JS对象消耗的内存与堆栈的使用情况;
- 检测页面脚本执行过程中CPU占用情况。
使用
console.profile()
和console.profileEnd()
就可以分析中间一段代码执行时的资源消耗情况。console.profile(); //执行测试页面的逻辑 for(let i=0; i<10000; i++){ console.log(i * i); } console.profileEnd();
-
页面埋点计时: 在JS代码中需要的位置添加时间戳,一般是在开始执行的位置添加时间戳,后面在需要记录的地方埋点记录结束时的时间戳,通过插值运算得出一段HTML或者JS代码解析执行的时间。为了方便操作,可以设置一个全局时间数组来进行记录。(p251)
-
资源加载时序图: 借助浏览器本身或者其他工具来查看资源加载的时序图,可以分析页面资源加载过程中的性能问题。可以宏观的分析资源文件请求耗时和文件 加载顺序 。(p252)
5.4.2 桌面浏览器前端优化策略 ★★★
-
网络加载类: (p253 - 256)
-
减少HTTP资源请求次数: 建议尽可能的合并静态资源图片、JS或CSS代码,减少页面请求数和资源请求消耗,这样可以缩短页面首次访问的用户等待时间;
-
减少HTTP请求大小;
-
将CSS或JS放到外部文件中,避免使用
<style>
或<script>
标签直接引入: 在HTML文件中引用外部资源可以有效的利用浏览器静态资源 ; -
避免页面中空的
href
和src
: 这两个属性为空时,浏览器在渲染过程中仍会将href
或src
属性中的空内容进行加载,直至加载失败,会阻塞其他资源的下载进程; -
为HTML指定Cache-Control或Expries: 为HTML内容设置Cache-Control或Expries可以将HTML内存缓存起来,避免频繁向服务器端发送请求;
-
合理设置Etag和Last-Modified: 合理设置Etag和Last-Modified使用浏览器缓存,对于未修改的文件,静态资源服务器会向浏览器端发送304,让浏览器从缓存中读取文件,减少web资源能下载的带宽消耗并降低服务器负载。
-
减少页面重定向: 每次重定向都会延长页面内容返回的等待时间,一次重定向大约需要600毫秒的时间开销。
-
使用静态资源分域存放来增加下载并行数: 浏览器同一时刻向同一域名请求文件的并行下载数是有限的,因此可以利用多个域名的主机存放不同的静态资源,来增大页面加载时的并行下载数。
-
使用静态资源CDN来储存文件;
-
使用CDN Combo下载传输内容;
-
使用可缓存的AJAX: 对于返回内容相同的请求,没有必要每次都直接从服务端拉取,合理使用AJAS缓存能加快AJAS响应速度并减轻服务器压力。
-
使用GET请求来完成AJAX请求: 浏览器的POST方法发送请求时首先发送文件头,然后发送HTTP正文数据。而GET请求只发送头部,所以在拉取服务器数据时使用GET效率更高。
-
减少Cookie的大小并进行Cookie隔离: HTTP请求通常会默认携带浏览器端的Cookie,所以在非必要情况下,要尽量减小Cookie,来减小HTTP请求的大小。对于静态资源,尽量使用不同的域名来存放,因为Cookie默认情况下是不可以跨域的,这样就做到了不同域名下的静态资源请求的Cookie隔离。
-
缩小favicon.ico并缓存;
-
推荐使用异步JS资源: 异步的JS资源不会阻塞文档解析,所以允许浏览器中优先渲染页面,延后加载脚本执行。
eg:
<script src="main.js" defer></script> <script src="main.js" async></script>
使用async时,加载和渲染后续文档元素的过程和main.js的加载执行是并行的。
使用defer时,加载后续文档的过程和main.js的加载时并行的,但是main.js的执行要在页面所有元素解析完成之后才会开始执行。
-
消除阻塞渲染的CSS及JS: 对于页面中加载时间过长的CSS或JS文件,需要进行合理拆分或延后加载,保证关键路径的资源能快速加载完成。
-
避免使用CSS @import 引用加载CSS。
-
-
页面渲染类: (p256 - 258)
- 把CSS资源引用放在HTML问价头部: 推荐写在HTML的
<head>
中,优先下载CSS文件,并尽早完成页面渲染。 - JS资源引用放在HTML文件底部: JS资源的默认是解析阻塞的,除非被标记为异步或者通过其它的异步方式加载,否则会阻塞HTML DOM解析和CSS渲染的过程。
- 不要在HTML中直接缩放图片: 会导致页面内容的重排、重绘,可能造成页面卡顿,尽量避免。
- 减少DOM元素的数量和深度: HTML中标签元素越多,层级越深,浏览器解析DOM并绘制浏览器中所花的时间就越长。
- 尽量避免使用
<table>
,<iframe>
等慢元素:<table>
元素的绘制是将table的DOM渲染树全部生成完成并一次绘制到页面上的,所以在长表格的渲染时很耗性能,尽量避免,可以考虑使用<ul>
代替。<iframe>
内资源的下载进程会阻塞父页面静态资源的下载与CSS及HTML DOM的解析,尽量使用异步的方式动态添加iframe。
- 避免运行耗时的JS: 会阻塞DOM树、DOM渲染树、渲染页面。
- 避免使用CSS表达式或CSS滤镜: 速度比较慢,在有其他解决方案的情况下尽量避免使用。
- 把CSS资源引用放在HTML问价头部: 推荐写在HTML的
- 2020/02/23
5.4.3 移动浏览器前端优化策略
-
网络加载类: (p258 - 260)
- 首屏数据请求提前,避免JS文件加载后才请求数据;
- 首屏加载和按需加载,非首屏内容滚屏加载,保证首屏内容最小化;
- 模块化资源并行下载;
- inline首屏必备CSS和JS: 将页面渲染时必备的CSS和JS通过
<style>
或<script>
内联到页面中,避免页面HTML载入完成到页面内容展示这段时间页面出现空白。; - meta dns prefetch设置DNS预解析 : 设置文件资源的DNS预解析,让浏览器提前解析获取静态资源的主机IP,避免等到请求时才发起DNS解析请求;
- 资源预加载;
- 合理利用MTU策略: TCP网络传输的最大传输单元(MTU)为1500B,即一个RTT(网络请求往返时间)内可以传输的最大数据量为1500B。所以尽量保证页面的HTML内容在1KB以内。
-
缓存类: (p260)
- 合理利用浏览器缓存;
- 静态资源离线方案: 对于移动端或Hybrid应用,可以设置离线文件或离线包机制让静态资源从本地读取,加快资源载入速度,并实现离线更新;
- 尝试使用AMP HTML: 使用AMP Component中的元素来代替原始的页面元素进行直接渲染。
-
图片类: (p206 - 262)
- 图片压缩处理;
- 使用较小的图片,合理使用base64内嵌图片: 需要注意的是,要保证图片较小,一般超过2KB就不推荐使用base64内嵌了。
- 使用高压缩比格式的图片;
- 图片懒加载;
- 使用Media Query或srcset根据不同屏幕加载不同大小的图片;
- 使用iconfont代替图片图标;
- 定义图片大小限制。
-
脚本类: (p262 - 264)
- 尽量使用id选择器: id选择器速度更快;
- 合理缓存DOM对象 : 对于需要重复使用的DOM对象,优先设置缓存变量存放;
- 页面元素尽量使用事件代理,避免直接绑定事件;
- 使用touchstart代替click;
- 避免touchmove、scroll连续事件处理: 连续触发事件可以设置事件流,例如设置每隔16ms(60帧的帧间隔是16.7ms)才进行一次事件处理(在事件的回调函数里面加setTimeout),避免频繁的事件调用导致移动端页面卡顿。
- 避免使用eval、with,使用join代替连接符+,推荐使用ES6的字符串模板;
- 尽量使用ES6+的特效来编程。
-
渲染类: (p264 - 265)
- 使用Viewport固定屏幕渲染,可以加速页面渲染内容: 一般认为,在移动端是指Viewport可以加速页面的渲染,同时可以避免缩放导致页面重排重绘;
- 避免各种形式的重排重绘;
- 使用CSS3动画,开启GPU加速: 设置
transform: translateZ(0)
来开启GPU图像处理加速; - 合理使用Canvas和requsetAnimationFrame;
- 不滥用 float: 在DOM渲染树生成后的布局渲染阶段,使用float的元素布局计算比较消耗性能,所以尽量减少float的使用,推荐使用固定布局或flex-box弹性布局的方式来实现页面元素布局;
- 不滥用web字体或过多font-size: 过多的font-size声明会增加字体大小的计算时间。
-
架构协议类: (p265)
- 尝试使用SPDY和HTTP2;
- 使用后端数据渲染;
- 使用Native View代替DOM性能劣势。