Skip to content

有哪些重要的性能的指标?

  • FP: First Paint (首次渲染时长)
  • FCP: First Contentful Paint (首次内容渲染时长/白屏时间)
  • FMP: First Meaningful Paint (首次有效渲染时长/首屏时间)
  • TTI: Time To Interactive (首次可交互时长)
  • PLT: Page Load Time (页面加载时长)

参考资料:

性能优化策略

  • 请求数量:合并脚本和样式表;CSS Sprites;拆分初始化负载,按需加载;划分主域等
  • 请求带宽:开启 GZip;分包;精简 JavaScript,移除重复脚本;图像优化等
  • 缓存利用:使用 CDN;使用外部 JavaScript 和 CSS;添加 Expires 头,配置 ETag;DNS 预解析,减少 DNS 查找;使 Ajax 可缓存等
  • 页面结构:预加载;预渲染;将样式表放在顶部,将脚本放在底部,尽早刷新文档的输出
  • 代码校验:避免 CSS 表达式;编写高效的 CSS 代码;避免重定向;节流&防抖

网络优化方向

  • 开启 HTTP2:首部压缩、多路复用、二进制格式传输信息
  • 域名收敛:最大化节省 DNS 解析,TCP 建连等网络成本
  • DNS 预解析:<link rel="dns-prefetch" href="//xxx.cdn.com/">,比较适合 CDN 域名场景
  • 提前建立网络连接:使用 preconnetlink 标签提前触发 DNS 解析、TCP 握手、TLS 加密信息验证等操作。适合可以判断页面有极大可能使用的网络连接(如 Server API );对于 CDN 的资源,由于缓存的存在大多数情况并不会发送资源请求,所以不适合进行 preconnet
  • brotli 压缩:谷歌在 2015 年发布 Brotli 压缩算法,相比 gzip,它具有更高的压缩比和更快的压缩性能
  • 支持 TLS 1.3:使用 TLS 1.3 协议只需要一次往返( 1-RTT )就可以完成握手,而使用 TLS 1.2 需要两次往返( 2-RTT )才能完成握手,然后才能发送请求。相比 TLS 1.2,TLS 1.3 的握手时间减半
  • 支持 HSTS:Strict-Transport-Security(简称HSTS)HTTP Header 会告知浏览器在和网站进行通信的时候强制性的使用 HTTPS,而不是通过明文的 HTTP 进行通信,注意是在浏览器端进行 HTTPS 重定向,这个会减少一次请求时间

参考资料:

如何达到 60fps?

  1. 避免没有必要的重排
  2. 避免没有必要的重绘
  3. 利用 GPU 加速渲染
  4. 构建更为流畅的动画
  5. 正确地处理滚动事件

结合浏览器渲染 Web 页面的过程来分析

参考资料:

页面 DOM 节点太多,会出现什么问题?如何优化?

前端需要渲染大量数据,这种情况下网页会出现掉帧、卡顿或假死等情况。

通常采用「虚拟列表」的方式来解决问题。

虚拟列表指的就是「可视区域渲染」的列表,重要的基本就是两个概念:

  • **可滚动区域:**假设有 1000 条数据,每个列表项的高度是 30,那么可滚动的区域的高度就是 1000 * 30。当用户改变列表的滚动条的当前滚动值的时候,会造成可见区域的内容的变更。

  • **可见区域:**比如列表的高度是 300,右侧有纵向滚动条可以滚动,那么视觉可见的区域就是可见区域。 实现虚拟列表就是处理滚动条滚动后的可见区域的变更,其中具体步骤如下:

    • 计算当前可见区域起始数据的 startIndex
    • 计算当前可见区域结束数据的 endIndex
    • 计算当前可见区域的数据,并渲染到页面中
    • 计算 startIndex 对应的数据在整个列表中的偏移位置 startOffset,并设置到列表上

如何做性能监控?

参考资料:

如何做前端错误监控?

监控:

  1. javascript 异常(语法错误、运行时错误、跨域脚本)
    • window.onerror 捕获 js 异常
    • 跨域脚本异常:一般涉及跨域的 js 运行错误时会抛出错误提示 script error,但没有具体信息(如出错文件,行列号提示等),可利用资源共享策略来捕获跨域 js 错误(客户端:在 script 标签增加 crossorigin="anonymous" 属性;服务端:静态资源响应头 Access-Control-Allow-Origin: *
  2. 资源加载异常(js, css):利用 window.addEventListener('error', cb, true) 捕获异常
  3. Ajax 请求异常:利用 xhr.onreadystatechange/xhr.onerror 统一拦截处理
  4. Promise 异常 promise 中的报错顺序是:如果有 catch 等捕获函数,则走 catch 捕获函数。catch 捕获函数如果没有抛出新的异常,则下一个 then 将会认为没有什么报错,会继续执行。如果没有 catch 等捕获函数,我们需要注册 window.addEventListener('unhandledrejection') 来处理
  5. Vue 项目中全局异常捕获:利用 Vue.config.errorHandler = function (err, vm, info) { ... } 捕获处理

上报:

js
function report (msg) {
    var reportUrl = 'http://xxxx/report'
    new Image().src = reportUrl + encodeURIComponent(JSON.stringify(msg))
}

前端监控/数据埋点使用 1x1 像素透明 gif图片进行上报主要原因是:

  1. 没有跨域问题,一般这种上报数据,代码要写通用的;(排除 ajax)
  2. 不会阻塞页面加载,影响用户的体验,只要 new Image 对象就好了;(排 除 JS/CSS 文件资源方式上报)
  3. 在所有图片类型中,体积最小,避免过多资源损耗;(比较 PNG/JPG)

在页面 unload 时,如果要上报当前数据,采用 xhr 的同步上报方式,会阻塞当前页面的跳转;使用 new Image有可能遇到 aborted,导致无法成功发送。

参考资料:

一个请求包含哪些时间消耗?

请求耗时示意图

  • Resource Scheduling,资源调度
    • Queueing: 请求任务调度排队耗时,浏览器同时处理很多请求,发送一个请求不是立即去发,是有一个调度过程的
  • Connection Start,建立连接
    • Stalled: 闲置时间,程序准备工作
    • DNS Lookup: DNS 查询时间
    • Initial connection: TCP 建立连接,3 次握手
    • SSL: SSL 连接
  • Request/Response,收发请求
    • Request sent: 发请求
    • Waiting (TTFB): 首字节返回等待
    • Content Download: 下载

浏览器同时处理很多请求,不能说你想发一个请求,就立即帮你发;它其实有一个调度过程的,浏览器也不是无限制的发送请求,通常一个 TCP 发送 6 个。