CoreJava XnMatrix rinetd ScrollView extjs6.5 button extjs gdb Semantic UI vue双向绑定 管理后台模板 swift视频教程 pmp教程 oracle一键卸载工具 linux环境变量生效 java算法培训 c语言求和 idea整理代码格式 java解析json数组 excel被保护怎么解除 汇编语言clr oracle分析函数 mysql新建数据库 python如何实现多线程 python代码示例 python位运算 python学习方法 java表达式 java多线程教程 java语言编程 莫愁脚本 战地2单机地图 黑帮之地修改器 怪物猎人ol捏脸数据 方正兰亭字体下载 win10有哪些版本 游戏python界面编程 pr蒙版 微信预约系统 qq浏览器手机
当前位置: 首页 > 学习教程  > 编程语言

前端性能分析与优化

2020/12/28 20:12:29 文章标签:

页面性能优化是前端绕不开的问题,本篇文章将讨论 如何进行页面性能优化怎样评价页面性能 浏览器加载过程 分析浏览器加载页面的过程,然后在其中的各个环节进行优化。 1.建立连接过程 DNS解析 浏览器查找域名的IP地址浏览器给web服务器发送一个HTTP请…

页面性能优化是前端绕不开的问题,本篇文章将讨论

  1. 如何进行页面性能优化
  2. 怎样评价页面性能

浏览器加载过程

分析浏览器加载页面的过程,然后在其中的各个环节进行优化。

1.建立连接过程

  1. DNS解析 浏览器查找域名的IP地址
  2. 浏览器给web服务器发送一个HTTP请求
  3. 服务器发送永久重定向响应
  4. 浏览器跟踪重定向地址
  5. 服务器“处理”请求
  6. 服务器发回一个HTML响应,返回相应的数据(html、css、js、图片等)

2. 浏览器渲染解析HTML

  1. 构建DOM树
  2. 渲染树构建
  3. 渲染树布局
  4. 绘制渲染树

优化思路

针对以上过程,可以用以下方式进行优化:

浏览器缓存

可以减少DNS查询和资源请求的时间。
 
浏览器要根据域名找出IP地址,而DNS查找过程的第一步是在浏览器缓存中查找,根据Chrome的PageSpeed给出的建议:要利用浏览器缓存存储可缓存的资源。在 HTTP 标头中为静态资源设置有效期或最长存在时间,可指示浏览器从本地磁盘中加载以前下载的资源而不是从网络中加载。 关于浏览器缓存,可以参考之前一篇

页面内容组织

① 为 HTML 文档指定字符集,可让浏览器立即开始执行脚本。  
② 将内嵌样式块和 元素从文档主体移至文档标题,可改善显示性能。  
③ 将小型样式表或者脚本内嵌到主 HTML 网页中,可减少在下载其他资源时的往返时间 (RTT) 和延迟时间。
④ 正确地排列外部样式表与外部和内嵌脚本的顺序,可增加下载时同时加载的数据量,并提高浏览器显示网页的速度。为确保能够并行下载这CSS 文件,始终将外部 CSS 文件排在外部 JavaScript 文件前面。

HTML

① 使用HTML5新标签,例如header、footer、section、nav、article。因为它们语义化,速度快,结构合理,浏览器上识别能力强。  
② 减少HTML标签嵌套深度,嵌套越深,在移动端的Web页面渲染速度以及滚动流畅度都会有所减低。  
③ 为图片指定大小,减少重排。  
④ 压缩HTML。

CSS

① 使用CssSprite将零星的背景图包含到一张图中,通过background-position来使它显示在正确的位置;只请求一张图,减少了HTTP请求的次数。  
② 模块化、精简css,提高复用率。  
③ 减少渐变、阴影的使用。  
④ 合理使用CSS3高性能动画,Translate3d支持硬件加速。  
⑤ 避免使用滤镜。  
⑥ 不使用@import。  
⑦ 合并和压缩CSS代码。

JavaScript

① 暂缓 JavaScript 解析,暂缓解析不需要的 JavaScript(等到需要执行时再进行解析),可以提高网页的初始加载速度。  
② 使用事件委托机制,避免频繁操作DOM节点。  
③ 模块化代码:SeaJs。  
④ 合并和压缩JavaScript代码。
6、 图片优化
① 图片时页面大部分加载时间所花的地方,在图片设计的时候应该考虑相应的图片大小和格式
② 压缩图片

以上是针对整个页面加载的过程给出的优化方向,但是如何评价优化效率呢?如果我们有能够分析页面性能的工具就好了,这样对比优化前和优化后的指标,就可以得到优化的具体提升值了。

性能分析工具

市面上有很多较为成熟的性能分析工具可以帮助我们分析页面性能。

基于网页分析工具:

  1. 阿里测
  2. 百度应用性能检测中心
  3. Web PageTest
  4. PingDom Tools
  5. GTmetrix

基于浏览器分析工具:

  1. Chrome自带工具F12
  2. Firefox插件:YSlow(Yahoo工具)
  3. Page Speed(google)

每个工具都有很多细分的指标用来评价页面性能,前端比较通用的指标有:

  • DNS查询耗时
  • TCP链接耗时
  • request请求耗时
  • 解析dom树耗时
  • 白屏时间
  • domready时间
  • onload时间

通过对比优化前和优化后的各项耗时,我们能对优化效果有一个较为详细且具体的评价。
这些分析工具是如何获得这些耗时信息的呢?

Web Performance API

Web Performance API 这个API 可以为我们提供性能分析所需要的数据。

Web Performance API允许网页访问某些函数来测量网页和Web应用程序的性能,包括 Navigation Timing API和高分辨率时间数据。

介绍下比较重要的几个属性和方法

performance.timing属性

是一个PerformanceTiming对象,包含延迟相关的性能信息。
完整的属性列表参考这个文档 PerformanceTiming

window.performance.timing里面有很多的性能相关的时间戳记录,我们来看一些常用的:

属性含义
navigationStart准备加载页面的起始时间
domainLookupStart开始进行dns查询的时间
domainLookupEnddns查询结束的时间
connectStartTCP连接开始
connectEndTCP连接完成
domInteractive解析dom树开始
domComplete解析dom树结束
loadEventEndonload事件结束的时间

fetchStart : 开始检查缓存或开始获取资源的时间
domLoading: loading的时间 (这个时候还木有开始解析文档)

关键指标
这样,我们就可以定出一些关键步骤耗时:

DNS查询耗时 = domainLookupEnd - domainLookupStart
TCP链接耗时 = connectEnd - connectStart
request请求耗时 = responseEnd - responseStart
解析dom树耗时 = domComplete - domInteractive
白屏时间 = domloading - fetchStart
domready时间 = domContentLoadedEventEnd - fetchStart
onload时间 = loadEventEnd - fetchStart

实际情况中,前端更关注的性能指标在首屏,比如:
HTML 加载完成时间
首屏图片加载完成时间
首屏接口完成加载完成时间

performance.now() 方法

该方法返回一个DOMHighResTimeStamp对象,该对象表示从某一时刻(译者注:某一时刻通常是 navigationStart 事件发生时刻)到调用该方法时刻的毫秒数。

将其与 Date.now() 做对比,能更好地理解这个属性的特定使用场景:

  1. performance.now() 以微秒(百万分之一秒)为单位的时间,比Date.now() 更加精准。

  2. performance.now() 的时间是以恒定速率递增的,不受系统时间的影响(系统时间可被人为或软件调整)。

  3. Date.now() 输出的是距离 1970 的毫秒数,而 performance.now() 输出的是相对于 performance.timing.navigationStart(页面初始化) 的时间。

  4. 使用 Date.now() 的差值并非绝对精确,因为计算时间时受系统限制(可能阻塞)。但使用 performance.now() 的差值,并不影响我们计算程序执行的精确时间。

window.performance.getEntries() 方法

window.performance.getEntries 调用后可以获取一个包含了页面中所有的 HTTP 请求的时间数据的数组.这个数组是一个按startTime排序的 PerformanceEntry 对象数组,数组成员除了会自动根据所请求资源的变化而改变以外,还可以用mark(),measure()方法自定义添加。PerformanceEntry 的详细文档参考 PerformanceEntry。

每个PerformanceEntry对象的属性中包含资源加载过程各个阶段的时间外,及以下五个可能有用的属性:

  • name:资源名称,是资源的绝对路径或调用mark方法自定义的名称
  • startTime:开始时间
  • duration:加载时间
  • entryType:资源类型,entryType类型不同数组中的对象结构也不同,所有的type可以查看 PerformanceEntry.entryType
  • initiatorType:发起的请求者

由以上,我们可以得出一些,我们比较关心的性能指标如下:

  • 首屏图片完成时间
  • 各资源耗时(主要统计css/js资源耗时)
  • FP(首次绘制时间)
  • FCP(首次内容渲染时间)

其与 performance.timing 对比的差别就是没有与 DOM 相关的属性。而要注意的是, HTTP 请求有可能命中本地缓存,这种情况下请求响应的间隔将非常短,数据可能不准确。

这个时候,我们可以自己手动加上一些时间点(这里的手动添加的点都推荐使用performance.now来实现),结合一起上报。代码示例如下:

//window.loadHtmlTime 在html中的</body>标签前面用打个时间戳即可
HTMLComplete = window.loadHtmlTime - window.performance.timing.navigationStart

//window.lastImgLoadTime 在首屏中的每张图onload之后都更新一次这个时间戳
firstScreenImgFinished = window.lastImgLoadTime - window.performance.timing.navigationStart

//Report.SPEED.MAINCGI 在首屏中的每个接口调用成功后更新时间戳
firstScreenApiFinished = Report.SPEED.MAINCGI - window.performance.timing.navigationStart

//在所有接口打时间点
apiFinishes = Report.SPEED.LASTCGI - window.performance.timing.navigationStart);

PerformanceObserver

当调用 window.performance.getEntries 这个方法的时候,我们得到的是调用方法前的所有资源的数据,一些资源可能有延时,或者在一些特殊的逻辑下才加载,这种情况下就需要轮询上报。

浏览器考虑到这些复杂的情况,提供了一个 PerformanceObserver, 用于监测性能度量事件,在浏览器的性能时间轴记录下一个新的 performance entries 的时候将会被通知.

PerformanceObserver() 构造函数使用给定的观察者 callback 生成一个新的 PerformanceObserver 对象.
当记录的性能指标在通过 observe() 方法注册的 entryTypes 之中时,将调用性能观察器的回调函数。
当通过 observe() 方法注册的 条目类型 的 性能条目事件 被记录下来时,调用该观察者回调.
看这个例子:

var observer = new PerformanceObserver(function(list, obj) {
  var entries = list.getEntries();
  for (var i=0; i < entries.length; i++) {
    // 观察到变化时的回调
  }
});
observer.observe({entryTypes: ["mark", "frame"]});
// 添加 mark 和 frame 类型事件的监听

function perf_observer(list, observer) {
  // Process the "measure" event
}
var observer2 = new PerformanceObserver(perf_observer);
observer2.observe({entryTypes: ["measure"]});

我们可以利用 PerformanceObserver 做到当有性能数据产生时,主动通知你(观察者模式),所以我们监听自己需要的资源类型,当有这个资源的时候进行上报即可。

总结

  1. 根据浏览器加载页面的过程,我们可以通过使用浏览器缓存、压缩资源、异步加载、按需加载等方式优化。
  2. 页面性能评价业内有常用的指标,可以通过浏览器工具或者第三方工具获得,其底层原理是利用了 window.perfomace 的 API。performace.timing 可以获取TCP链接、request请求、解析dom树耗时间、白屏时间、domready时间、onload时间。performance.getEntries() 方法可以获取首屏图片完成时间、各资源耗时(主要统计css/js资源耗时)
    、FP(首次绘制时间)、FCP(首次内容渲染时间)等。
  3. 浏览器提供的 PerformanceObserver 对象可以帮助实现页面性能监听,可用于实现前端性能监听体系的搭建。

参考文献

  1. MDN Web Docs: Performance
  2. Web页面性能测试工具浅析
  3. 前端性能优化之自定义性能指标及上报方法详解

本文链接: http://www.dtmao.cc/news_show_550437.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?