前言
给你一个网站,你如何知道它的性能优化做的怎么样?
工作中做过哪些性能优化方面的尝试?
面试中,往往会面临上面的灵魂拷问~~~ 我之前一直不明白面试官老问我这个干嘛?就非得是面试造火箭,工作拧螺丝吗!
后来,一个大佬解答了我的疑惑,这问题是一个很开放性的,包括了浏览器渲染过程、CSS/JS阻塞、重绘、重排、SSR、打包体积优化等很多知识点,可以层层递进,快速分别出面试者掌握的知识体系。
本文的重点会从性能监控
和性能优化
方面入手。
正文开始
1,Navigation Timing API
是浏览器提供的API,主要用于获取与网页加载过程各个阶段的时间和性能指标。
比如想知道当前页面加载耗时,用法如下
下图是网页加载过程中的三个主要阶段,和对应的API分布。小伙伴们大概知道怎么回事就行,不需要刻意记住API名字,太长了,足以应付面试了。
接下来,对各个API进行一个解释,最后再来两个常见案例。
1.1,navigationStart
- 前一个文档卸载时的时间戳 (如果无上一层页面时,从fetchStart开始)
1.2,unloadEventStart / end
unloadEventStart和unloadEventEnd的简写,下面的API同理
- 前一个页面的unload时间戳
- 无前置页面时? => 值为0
- 前置页面域不同 => 值为0
navigationStart 和 unloadEventStart 的区别
这两个有点像,容易搞混。
-
navigationStart 取值先于 unloadEventStart
-
navigationStart 不限域,就是说,跨域的跳转也存在值,而 unloadEventLoad 必须是同域下的跳转才有值
1.3,redirectStart / end
- 第一个http重定向发生的时间 / 最后一个http重定向完成的时间
- 有跳转且是同域名不同页面 => 否则值为0
- 单页面应用中,比如vue里通过router.push跳转的值为0
1.4,fetchStart
- 浏览器准备好使用HTTP请求抓取文档的事件
1.5,domainLookupStart / end
- 开始/重新建立连接的时间(只是
建立
) - 如果是长链接 => 值等于fetchStart
- 因为长连接不需要缓存,检查是否过期之类的
1.6,connectStart / end
- TCP建立握手的开始 、 完成
- 如果是长链接 => 值等于fetchStart
- 因为长连接不需要缓存,检查是否过期之类的
1.7,secureConnectionStart
- HTTPS连接建立开始时间
1.8,requestStart / end
- 请求发起的真实时间
- 读取本地缓存(强缓存/协商缓存)也会发起请求,也有值
1.9,responseStart / end
- 请求返回数据的真实时间
- 读取本地缓存(强缓存/协商缓存)也会发起请求,也有值
1.10,domLoading
- 开始解析渲染DOM树 => 抛出readystatechange事件
1.11,domInteractive
- 完成了DOM树的解析 => 抛出readystatechange事件
- 这个时候并没有开始加载网页资源,比如echart,css,js
1.12,domContentLoadedEventStart / end
- DOM解析完成后,开始 / 结束加载网页内资源的时间
1.13,domComplete
- 整体DOM树解析完成 => 抛出readystatechange事件
1.14,loadEventStart / end
- load事件发送给文档 / 回调执行完成的时间
- 网络资源加载完成,dom渲染完成,可以获取canvas 的dom去渲染echarts
常见问答
网络请求的时间段
- domainLookupStart - responseEnd 的阶段
- responseEnd 减去 domainLookupStart得到的时间戳就是网络请求所花费的时间,下同理
静态渲染花费的时间段
- domLoading - domComplete 的阶段
动态渲染,所有文件加载完渲染花费的时间段
- domLoading - loadEventEnd 的阶段
一个网站的性能如何,通过上面的API进行相减就能计算出来了。
学到这里,再加上你自己脑子里零碎的其他性能优化片段,其实针对很多中小厂面试就可以了。
下面会从Google
提出的 Core Web Vitals
性能指标继续分析网址的性能,并给出大概解决方案~~
知识点有点零碎,不过这已经是提炼过之后的了,还有精力的小伙伴可以继续看下去~~~
2,Core Web Vitals 网页核心的性能指标
Google
提出的网页核心的性能指标,主要从加载、交互、视觉稳定性对一个网页进行性能打分。
2.1,LCP - Largest Contentful Paint 衡量渲染性能
- 衡量加载性能 - 前2.5s内进行最大内容的渲染
最大内容是神马东西?**
<img>
元素<svg>
元素<video>
元素- 通过
url()
函数加载背景图片的元素 - 包含文本整体节点的块级元素
什么导致了LCP值低呢?
- 服务器响应慢
- 阻断渲染的JS和CSS
- 资源加载慢
- 客户端渲染机器性能影响
🎉 提高LCP值的方法
-
使用
Service Worker
缓存HTML离线页面,强缓存
、协商缓存
缓存页面资源,减少浏览器对于资源的请求 -
尽量减少资源组端渲染,减少重绘重排:CSS和JS做级联、内联、合并
-
对图片进行优化 JPG WEBP => 降低资源大小 => 加快请求速度
-
使用CDN加快请求速度 云资源管理
-
利用工程化做项目优化 => HTML进行重写优化、ugliyfy压缩空格、去除注释、去除打印、调整格式
-
提升首屏优化 => 懒加载、Tree Shaking资源按需加载、service worker、服务端渲染(SSR)
2.2,FID - First Input Delay
- 衡量交互性能 - 页面首次输入的延迟应该小于100ms
🎉 提高FID值的方法
减少JS执行时间
- 缩小并压缩JS文件
- 延迟执行不需要的JS
- 尽量减少用不到的polyfill
分解耗时的任务
- 任何阻塞主线程超过50ms => 长任务
- 长任务拆分成较小的异步任务
- 把同步的长任务,分解成若干个异步任务
- 优化算法降低复杂度,提升性能
- 优化逻辑数据结构处理
worker:和长任务分解有点像,让主流程快速通行,减少输入的延迟
-
web worker / service worker
-
相同点
- 不能操作DOM
- 运行在独立的线程中,不阻塞主线程
-
不同点
- web worker通过主子线程可以多线程处理,适用于执行复杂任务。 一部分活自己干,一部分分给工人干
- service worker没有主子线程的概念。适用于处理网络请求、缓存数据和离线功能
- 业务场景:service worker也能实现在线聊天,不过它不是实时的,而是通过缓存去取数据推给客户端
// 1. web worker
// main.js
const myWorker = new Worker('worker.js');
// 与mainthread之间通信
myWorker.postMessage('hello');
myWorker.onmessage = function(e) {
console.log(e.data);
}
// worker.js
self.onmessage = function(e) {
console.log(e.data);
self.postMessage(workerResult);
}
// 2. service worker
// main.js
navigator.serviceWorker.register('./service-worker.js');
// serveice-worker.js
self.addEventListener('install', event => {})
self.addEventListener('activate', event => {})
self.addEventListener('fetch', event => {
event.respindwith(
caches.match(event.request)
)
})
2.3,CLS - Cumulative Layout Shift
-
衡量视觉稳定性 - CLS页面应当保持在小于0.1
-
布局的移动可能发生在可见元素从一帧到下一帧改变的位置
- 左右布局的一个页面原本比例是5:5,突然变成9:1,就会对值有影响
🎉 提高CLS值的方法
不使用无尺寸元素
- srcset & sizes
- srcset设置不同图片
- sizes根据不同屏幕适配不同大小
<img srcset"image.jpg300w,image.jpg100w" sizes"(max-width:600px)600w,(max-width:1000px)1000w">
减少内容的插入
- 影响整体的布局
动态字体控制
-
积少成多,字体的变化有时候也很影响
CLS
的值- 比如网页默认使用
Arial
,但是某个页面要用微软雅黑
,如果浏览器已经预加载了微软雅黑
,那么就可以快速渲染页面,如果没有预加载,那么浏览器就会先使用Arial
,过了一会变成微软雅黑
- 比如网页默认使用
-
<link rel="preload"> - 预加载字体
2.4,CWV 工具
Chrome
开发者工具中的Lighthouse面板
上图可以看到LCP
微微有点高,CLS
表现比较好
-
Core Web Vitals Annotations
Google
提出的计算Core Web Vitals
网页核心的性能指标的工具,是Chrome商店的一个浏览器插件
3,性能优化的另一种可能 - bigpipe
页面分解成若干的pagelet(片段)
- 服务前端接收来自客户端HTTP请求
- 存储层(有点Service Worker的影子)去获取数据 => 组装HTML,渲染基本完成的页面 => 响应给客户端
- 有点类似Vite + SSR
- 类似Vite的ESM分片渲染,然后服务端组装成HTML,给到客户端
总结
本文主要介绍了面试中关于性能监控和优化
涉及到的知识点。
从浏览器API Navigation Timing API
计算页面不同阶段花费时间 到 Core Web Vitals
网页核心的性能指标的三大项(LCP、FID、CLS)和优化方案。
知识点可以说非常零碎而且多了。
汇总一下提升性能的方案就是
开发部分 => 减少重绘重排
打包部分 => 减少文件大小
部署和展示部分 => 提升加载和反馈的效率
其实,关于减少重绘重排
,还有一部分浏览器渲染环境的知识点,有时间再小伙伴们罗列吧。
完结
这篇文章我尽力把我的笔记和想法放到这了,希望对小伙伴有帮助。
欢迎转载,但请注明来源。
最后,希望小伙伴们给我个免费的点赞,祝大家心想事成,平安喜乐。