0%

优化1.性能优化的指标和工具

性能指标和优化目标

Network

  • Queueing:资源需要经过排队才能从浏览器发出去,浏览器会对资源请求进行优先级安排,高优先级的内容先安排进行请求

  • DNS Lookup:每个资源实际上有个域名,域名最终要被翻译成 IP,然后找到这个服务器

  • initial connection:找到资源之后,客户端与服务器建立链接的过程

  • SSL:有的网站是 https,为了安全性,使用了 SSL 证书,需要进行安全性验证,过程称为 SSL 写上

  • Request sent:请求发送出去

  • Waiting(TTFB):发送出去请求到资源真正回来中间的等待时间,请求发出去到请求回来经历多久的时间,如果 TTFB 高的话,相当于请求发出去了,资源一直没回来,浏览器就是白屏

    主要影响因素:后台的处理能力,服务器响应有多快;其次是资源,发送出去请求,回来到底会不会有延时

  • Content Download:下载,如果蓝条越长,资源就越大,等待的时间就越长。如果本身一直在下载,后面的资源都无法加载

  • DOMContentLoaded:DOM 加载完成时间

  • Load:页面上所有资源加载完成时间

如果 Network 内容较多,可以先把结果保存下来,右键点击空白处,Save all as HAR with content

Lighthouse

指标

  • Performance:性能
  • Accessibility:可访问性
  • Best Practices:最佳实践
  • SEO:对搜索引擎有没有做优化
  • Progressive Web App(PWA):渐进式应用价值,包括离线也能给客户进行访问

度量(Metrics)

  • First Contentful Paint:第一个有内容的绘制出现的时间
  • Speed Index:速度指数,速度指数标准是 4s

交互体验

在 Network 里按 Ctrl + Shift + P,输入 frame,选择下图红框

会在左上角出现监控

RAIL 测量模型

  • Response 响应
  • Animation 动画
  • Idle 空闲
  • Load 加载

响应

  • 处理事件应在 50ms 以内完成
  • 用户能接受最高延时是 100ms,所以所用的用户操作,必须在 100ms 内反馈(当用户进入交互到进行输入之后一直给出反馈所经历的时间)

动画

  • 每 10ms 产生一帧
  • 浏览器去获取每一帧实际上也要些时间,大概是 6ms 左右

空闲

  • 尽可能增加空闲时间
  • 如果前置时间 50ms,处理时间 50ms,那用户的交互栏根本没时间去处理,用户点击后就会感觉卡住了,后面要用到的内容利用空闲时间慢慢记载即可

加载

  • 在 5s 内完成内容加载并可以交互
  • 一个层面:要完成内容加载,这 5s 不光是加载这么简单,加载完了还要解析,解析完了还要进行渲染,所有这些时间都算在内;另一个层面:使用移动设备,网络环境可能比较差,比如使用 3G

性能测量工具

  • Chrome DevTools:开发调试、性能评测
  • Lighthouse:网站整体质量评估
  • WebPageTest:多测试地点、全面性能报告

WebPageTest

网站:WebPageTest

  • Test Loaction:测试地址
  • Browser:浏览器
  • Connection:配置网络连接情况
  • Number of Tests to Run:测试轮数
  • Repeat View:结果视图,通常选择 First View and Repeat View,用户首次访问页面和第二次访问,通过这两个视图对比,可以看出缓存做的好不好
  • Capture Viedo:捕捉视频,可以直观通过这个视频了解你的用户在这个指定设备访问的体验

  • First Byte:发出去的第一个请求,它得到响应的时间是多久,反应了后台的处理能力和网络回路的情况
  • Start Render:首屏时间,指看到内容所需时间,而不是一直白屏
  • Speed Index:速度指数(4s 以内)
  • Total Blocking Time(TBT):页面被阻塞住了,用户不能进行交互,这个时间累积有多长

  • Waterfall View:点击瀑布图可以查看详细信息

  • Browser Main Thread:主线程占用情况
  • CPU Utilization:带宽、CPU 的占用情况
  • 图片资源有并行同时家长,极大节约了时间
  • 可能会有黄色背景的,后面标着(302),之前资源已经不再请求位置了,需要重定向才能找到真实位置,这就提示我们这个地方可以优化

部署 WebPageTest

Windows10 下打开 Docker Desktop,之后拉取镜像

1
2
docker pull webpagetest/server
docker pull webpagetest/agent

拉取完镜像后,就可以来运行一下

1
2
docker run -d -p 4000:80 webpagetest/server
docker run -d -p 4001:80 --network=“host” -e “SERVER_URL=http://localhost:4000/work/” -e “LOCATION=Test” webpagetest/agent

Windows 电脑配置到这即可使用,MacOS 还需要做一些其他配置

  • 先是做 Server 配置
1
2
mkdir wpt-mac-server
cd wpt-mac-server

vim Dockerfile 创建文件并对其进行编辑添加如下内容:

1
2
FROM webpagetest/server
ADD locations.ini /var/www/html/settings/

vim locations.ini 创建文件并对其进行编辑添加如下内容:

1
2
3
4
5
6
7
8
9
10
[locations]
1=Test_loc
[Test_loc]
1=Test
label=Test Location
group=Desktop
[Test]
browser=Chrome,Firefox
label="Test Location"
connectivity=LAN

本地 build 镜像

1
docker build -t wpt-mac-server .
  • 再是做 Agent 配置,vim Dockerfile 创建文件并对其进行编辑添加如下内容:
1
2
3
FROM webpagetest/agent
ADD script.sh /
ENTRYPOINT /script.sh

vim script.sh 创建文件并对其进行编辑添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
set -e
if [ -z "$SERVER_URL" ]; then
echo >&2 'SERVER_URL not set'
exit 1
fi
if [ -z "$LOCATION" ]; then
echo >&2 'LOCATION not set'
exit 1
fi
EXTRA_ARGS=""
if [ -n "$NAME" ]; then
EXTRA_ARGS="$EXTRA_ARGS --name $NAME"
fi
python /wptagent/wptagent.py --server $SERVER_URL --location $LOCATION $EXTRA_ARGS --xvfb --dockerized -vvvvv --shaper none

之后给脚本添加执行权限

1
chmod u+x script.sh

之后本地 build 即可

1
docker build -t wpt-mac-agent .

通过 docker ps 查看所有运行实例,docker stop xxx 即可停掉实例

LightHouse

1
2
npm install lighthouse@6 -g
lighthouse http://www.bilibili.com

使用后会打开一个浏览器进行测试,测试完浏览器会自动关闭,生成 html 输出结果生成到 Printer html output written: ...,将地址拷贝到浏览器即可看到测试报告内容

下面看一下网站的性能

  • First Contentful Paint:第一个有内容的绘制时间
  • Speed Index:速度指数,页面上所有可见内容多久让用户看到
  • Largest Contentful Paint:所有可见资源里最大那个花了多久看到
  • Time to Interative:什么时候用户可以和你的网站进行交互

Opportunities 会提供一些优化建议

  • Remove unused Javascript:移除没有用到的 JS
  • Eliminate render-blocking resources:减少渲染阻塞资源,要看下这个 JS 是否可以延迟加载

如何确认某一个 JS 是不是必须的,之后增加不让加载的规则比如:log*.js,再重新加载,发现 log*.js 无法加载,再去首屏内容看是否受到影响

使用 Chrome DevTools 分析性能

Network 里每个资源都有一些属性:资源名称、大小、总耗时

  • 当后台开启压缩(express 使用 compression 中间件)就可以死对网络传输资源进行压缩
  • 实际大小虽然是 1.4M,单网络传输时只有 429K,大大减少了网络传输资源的大小

Performance 点击实心圆开始记录,在这个过程中页面发生的一切包括你的交互,都会被记录下来,直到你点击停止之后,这段过程中发生的一切都会出一个详细的性能报告;还有一种方式是点击刷新按钮,就会刷新我们的页面,记录页面从开始刷新一直到整个所有资源加载完成这个过程所发生的一切,然后进行性能分析

  • Main 主线程,可以看到随着时间推移,主线程都做了哪些任务。它是自上而下类似堆栈结构,每个调用关系都清晰表示出了,比如我们做个 Task,Task 里面会有一些相关的调用,一层层把我们的调用关系都列出来,一直到最后
  • Timings 关键事件节点,DCL 就是 DOM 加载完成时间,它发生之前都做了什么

网络吞吐:可以调整我们现在的网络状态,模拟用户网络情况

  • Download:4G 下载速度大概在 5~12M
  • Upload:4G 上行速度一般是 2~5M
  • Latency:延迟需要考虑用户所在位置的信号

常用性能测量 APIs

性能测量工具都有一些关键的时间节点,比如:TTFB、首屏,这些时间节点是通过浏览器

1
2
3
4
5
6
7
8
// load事件后触发
window.addEventListener('load', e => {
// Time to Interactive 可交互时间
let timing = performance.getEntriesByType('navigation')[0]
// 计算 tti = domInteractive - fetchStart
let tti = timing.domInteractive - timing.fetchStart
console.log('TTI', tti)
})

performance API 一些常用时间计算规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// DNS 解析耗时:
domainLookupEnd - domainLookupStart
// TCP 连接耗时:
connectEnd - connectStart
// SSL 安全连接耗时:
connectEnd - secureConnectionStart
// 网络请求耗时 (TTFB):
responseStart - requestStart
// 数据传输耗时:
responseEnd - responseStart
// DOM 解析耗时:
domInteractive - responseEnd
// 资源加载耗时:
loadEventStart - domContentLoadedEventEnd
// First Byte时间:
responseStart - domainLookupStart
// 白屏时间:
responseEnd - fetchStart
// 首次可交互时间:
domInteractive - fetchStart
// DOM Ready 时间:
domContentLoadEventEnd - fetchStart
// 页面完全加载时间:
loadEventStart - fetchStart
// http 头部大小:
transferSize - encodedBodySize
// 重定向次数:
performance.navigation.redirectCount
// 重定向耗时:
redirectEnd - redirectStart

通过 performance 实时监测对象

1
2
3
4
5
6
7
// 通过PerformanceObserver得到所有long tasks对象
let observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
console.log(entry)
}
})
observer.observe({ entryTypes: ['longtask'] })

加入你做的是视频网站,如果用户不再看你这个页面了,这时候需要考虑节流,不再进行视频内容的加载(可以在页面上进行 Tab 切换测试)

1
2
3
4
5
6
7
8
9
10
11
12
let vEvent = 'visibilitychange'
if (document.webkitHidden !== undefined) {
vEvent = 'webkitvisibilitychange'
}
function visibilityChange() {
if (document.hidden || document.webkitHidden) {
document.title = 'Web page is hidden'
} else {
document.title = 'Web page is visible'
}
}
document.addEventListener(vEvent, visibilityChange, false)

如果知道用户当前网络状态,就可以有针对性资源加载。比如用户网络状态不好时使用稍微模糊的图片(去 Network 去控制网络吞吐进行测试)

1
2
3
4
5
6
let connection = navigator.connection || navigator.mozConnection
let type = connection.effectiveType
function updateConnectionStatus() {
console.log('connection type changed from' + type + 'to ' + connection.effectiveType)
}
connection.addEventListener('change', updateConnectionStatus)