思考:
从A页面 到B页面,会经历哪些步骤?
- 离开A页面
- 路由重定向,指向B页面
- webworker 主从线程 master and slave MS线程 init
- 网络初始化 http socket等
- 页面layout tree,节点组装+样式+逻辑对节点的改变 重排
- processing 重绘和对layout-tree的一些逻辑处理
跳转特别慢,如何优化?
首先需要知道到底是哪一步特别慢,可以利用浏览器提供的钩子埋点,检测每个步骤的耗时:
chrome提供的performance
navigation timing API - 测量页面加载速度,采集每一个步骤所需时间
常用API如下:
- 1. navigationStart
- 上一个页面卸载结束时触发,如果新页进入就相当于 fetchStart
- 2. unloadEventStart /end
- 标识前一个网页unload的点,新页进入,这个值为0
- 3. redirectStart / end
- 标识一个重定向的持续时间
- 4. fetchStart /end
- 浏览器准备好使用http请求抓取文档的时间,文件打包大小之类的优化
- 5. domainLockupStart /end
- 页面请求http(包含TCP)开始和重新建立连接的时间,把一些请求后置减少这段时间,逻辑线程会block渲染线程
- 6. connectStart / end
- 网络请求建立和持续的时间,持久连接的话 相当于 fetchStart
- 7. secureConnectionStart / end
- https连接所用时间,衡量http和https时间差
- 8. requestStart /end
- 连接请求的时间 包含 from cache,从缓存中读取数据
- 9. responseStart / end
- 返回持续时间 包含 from cache
- 10. domLoading
- 开始解析渲染dom树 dom的 readyState,当dom渲染时这个值变成loading时 会抛出readystatechange readyState发生变化
- 11. domInteractive
- dom树解析完成 readyState 值变为 interactive 也会触发readystatechange
- 12. domCotentLoadedEvebtStart / end
- 网页资源加载时间 js脚本之类的
- 13. domComplete
- 逻辑执行完毕,资源就绪,dom树解析完成的点
- 14. loadEventStart / end
- load事件回调的时间
在这些地方埋点 就可以采集每个阶段所用时间,定位需要优化的点,比如可以人为计算一些时间,设置一些阈值,超过一定阈值之后做一些操作,比如邮件警告,办公软件提示等。
代码中可以用 window.performance.timing 来获取时间:
javascript: (() => {
const perfData = window.performance.timing;
const pageLoadTime = perfData.loadEventEnd - perfData.navigationstart;
console.log("页面加载耗时:",pageLoadTime,'ms');
})();
如何评定加载速度是否合适?衡量标准是什么呢?
Core Web vitals - 网页核心的性能指标
* Google提出的衡量标准,每个CWN代表用户体验的一个不同方面
大致从加载速度 | 交互友好 | 稳定性三个方向,将加载速度描述为可衡量的,并反映真实体验:
1. 衡量加载速度 Largest Contentful Paint(LCP)
衡量装载性能。为了提供良好的用户体验,LCP应该在页面首次开始加载后2.5秒内发生,即前2.5s内进行最大内容渲染。
2. 最大内容包括哪些?
- - <img>元素
- - <svg>元素
- - <video>元素
- - 通过url()函数加载的背景图片元素
- - 包含文本节点或者其他内联文本元素子集的块级元素
3. LCP值低下的原因
- - 服务器渲染慢
- - 阻断渲染 JS和CSS 单线程主从机制互相block
- - 资源加载时间慢 静态资源
- - 客户端渲染机器的性能
优化方案: 针对性的改造
1. 服务器优化:
- 缓存html离线页面,缓存页面资源,减少浏览器对资源的请求消耗(强缓存、协商缓存)
- 尽量减少阻断渲染:
- CSS和JS在文件层面进行压缩 合并 级联 内联,减少串联型处理,后置逻辑
比如点击下一步的动作,可以放在第一步渲染完之后才做,把不必要第一次渲染的逻辑后置
2. 图片和视频等资源优化:
图片:格式优化:JPG和WEBP,降低图片的大小,加快请求的速度
交互:点击播放键才播放视频,点击之前后台加载,优化一些用户体验
3. 客户端优化
文件解析方式:减少文件大小,减少逻辑操作,优化算法复杂度
webpack plugin
script标签里的async preload gzip
服务端渲染同构
2. 衡量交互性 First Input Delay (FID)
为了提供良好的用户体验,页面的FID应该小于100ms
* 页面的首次输入延迟应当小于100ms
刷新页面一定时间内input为什么不能输入?因为渲染没有完成,输入组件模块的加载没有完成,依赖于js 的执行。
优化方案:
1. 减少js 的执行时间
- - 缩小并减少js文件的大小
- - 延迟或者取消部分不必须的逻辑文件,比如输入校验之类的逻辑,比如vue可以放在mounted之后再做一些处理,与doom的渲染错开
- - 尽量减少或者按需加载 polyfill 即逻辑嵌套
2. 分解耗时的长任务
- 任何阻塞主线程50ms以上的都可以称作长任务,
将长任务拆分为若干较小任务并异步执行,或者后置到下次渲染开始执行
比如settimeout转换为nextTick
利用worker
- js worker: web worker | service worker
给我们一个小帮手,通过主从线程协作的方式把一个复杂的会阻塞主线程的方法简单化,获得更快的加载速度。
// 1. web worker
// main.js
// 新增worker
const myWorker = new Worker('worker.js')
//与main thread之间的通信
myWorker.postMessage('hello')
myWorker.onmessage = fuction(e) {
console.log(e.data)
}
// worker.js
self.onmessage = function(e) {
console.log(e.data)
// 处理
self.postMessage(workerResult)
}
这样就可以将myworker中的一部分操作分发到worker.js里去做,将任务分解
service worker
// main.js
navigator.serviceWorker.register('./service-worker.js')
// service-worker.js
self.addEvenListener('intall',function() {
// do sth
})
self,addEvenListener('activate',function() {
// do sth
})
// 网络请求
self.addEvenListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
)
})
// 面向网络和cache处理响应逻辑
如何区分这种网络请求和普通的axios请求?
如果主从线程都需要用到一些请求,那么通常放到主线程里,将数据分发到从线程,如果从线程可以独立地做一套完整的请求和处理,就可以在从线程中发起请求,将后续操作返回给主线程即可。
3. 衡量视觉稳定性 Cumlative Layout Shift(CLS)
为了提供良好的用户体验,页面应该保持CLS小于0.1
* 布局的移动可能发生在可见元素从前一帧到下一帧改变的位置
如何优化
1. 不使用无尺寸元素 特别是根据数据变化渲染的内容
srcset & sizes
<img
srcset="img-320w.jpg 320w,
img-480w.jpg 480w,
img-800w.jpg 800w"
sizes="(max-width: 320px) 280px,
(max-width: 480px) 440px,
800px"
src="img-800w.jpg"
/>
根据图片源可能的尺寸进行固定大小展示,不会因为变大变小而发生改变。
2. 减少内部内容的插入,影响整体的布局
比如大小固定后可以通过滚动等来控制,不会对布局产生影响
3. 动态字体控制
先默认字体展示占位,下载完成之后再动态替换
@font-face {
font-family: 'xxx';
font-style: normal;
font-weight: 400;
src: local('xxx Regular'), local('xxx Regular'), url('https://fonts.xxx.com/xxx.woff');
font-display: swap;
}
<link rel="preload"> // 预加载字体
这样就可以先用本地的字体展示出来,布局完成,等到远端字体下载完毕再去替换
CWV工具
安装后可以在浏览器看到实时性能
Core Web Vitals Annotations
性能优化的另一种可能性 - bigpipe - 页面分解成若干个pagelet
1. 服务前端接受来自客户端的http请求
2. 存储层缓存获取数据
3. 生成HTML,响应给客户端 + 客户端渲染
4. 动态区隔解析内容
大厂监控体系
埋点上报 点到点 + 信息采集
数据清洗 阈值设置 | 数据分类(加载 渲染 网络 操作类型的数据)不同维度的分析 | 数据重组 能够在展示平台展示的数据视图
可视化展现
自研报表监控
可视化面板展示 grafana
告警处理
告警触发
告警的分派 办公软件通知
面试tips:
结合自己的项目,你遇到什么样的问题,是怎么解决的,监控体系是怎么实现。