优化对象
此次优化是针对,Web 端视频播放页面。白屏工夫依照播放视频状态有两种状况,别离是:
-
内部进入,包含筛选页进入、分享链接进入、用户详情页进入和页面强制刷新,此时白屏工夫能够了解为浏览器输出 url 到播放器播放的工夫,次要流程分为四局部:
- 齐全白屏,FP(First Paint)之前流程
- 初始渲染视图和 loading 呈现,sessions 接口申请极其依赖逻辑执行
- sessions 之后的流程
- loading 隐没,开始播放
-
外部切换,通过手动点击【用户会话】列表项切换视频,此时白屏工夫能够了解为 loading 呈现到隐没的阶段,有三局部:
- loading 呈现
- sessions 之后的流程
- loading 隐没,开始播放
整顿流程图示如下:
预期后果
失常状况下,新版本视频指标达到 秒开,老版本视频因为须要手动解析事件,可能会稍慢一些。
已做工作
- 事件流分页(加载第一页数据后即开始播放)
- 提前渲染,不期待数据筹备结束,第一工夫渲染播放器、会话列表和事件流框架,播放前展现 loading,给用户视觉上更好的体验,「感觉快」
-
引入 Web Worker
- 新版本视频因为返回数据为字符串,须要手动解析为 JSON,因而下载和解析逻辑移入 Web Worker,充分利用 CPU 资源,防止影响主线程逻辑和渲染,播放前次要是不影响数据流,事件流的解析和渲染。
- 老版本视频下载和解析逻辑移入 Web Worker。
- 全页面去掉自定义滚动条
- 开发者工具 source 面板懒加载
整体剖析
借助 Chrome Performance 录制白屏至视频开播之间的片段,进行剖析:
因为 FP 用于记录页面第一次绘制像素的工夫,之后即会进入动静代码阶段,所以上面以 FP 为界线,别离剖析前和后两局部。
FP 之前剖析
上面是 FP 之前的详情截图
从图中能够看出耗时的工作次要为两局部:
- my-details.js 文件下载(目前 gzip 压缩之后,体积为 737.25 KB)
- 一个大 Task
问题定位
- 文件下载阶段,打包文件过大,通过 webpack 的打包插件 webpack-bundle-analyzer 剖析,如图所示:
通过剖析,三个最大的文件是 ts.worker.js(gzip 1010.22 KB)、my-details.js(gzip 737.25 KiB)和 chunk-vendor.js(gzip 442.56 KiB),三个大文件中的较大模块如下:
其中 monaco-editor 是最大的一个问题点。
- js 文件执行阶段,具体分析下大 Task,Performance 放大截图如下
剖析 Task 执行程序,执行流程图如下(只列出次要流程,打包之后执行流程会不同,但不影响剖析):
联合 Performance 后果,能够看出其中 monaco-editor 依然是最大的问题点。
进一步剖析问题如下:
chunk-vendor.js
是我的项目所有的依赖库,从它是打包了node_modules
能够看出,所以很影响性能monaco-editor
编辑器占了很大体积- 对于一些其余的工具库,未采纳按需引入的形式
优化计划
优化 FP 指标,要害是缩短资源的下载工夫,以及缩小阻塞浏览器渲染 DOM 的工作的执行工夫,通常来说的伎俩有骨架图、分块加载、缓存、缩小同步 js 代码、资源压缩和资源按需加载等等。对咱们来说大部分工作曾经做了,当初关键点为有几个文件很大。
因而,总结下优化计划:
- 拆分过大 js 文件,尤其是
monaco-editor
的抽离,因为用的中央太多了,导致很难做成按需加载了的了,能够应用splitChunks
拆散代码并实现相干模块共享。独自打包monaco-editor
,最终缩小申请资源的大小和申请次数 - 替换过大的第三方类库,次要是 lodash.js 和 moment.js
- 工具库采纳按需引入的形式,尤其是 element-ui
- 缓存局部动态资源,进步加载速度
ps: Webpack 调优已实现,补充文档 webpack 性能调优报告
FP 之后剖析
问题定位
FP 之后就进入了代码执行阶段,上面为 8 个会话依照几个重要节点进行耗时统计的柱状图:
由柱状图能够看出,vue 数据处理和 dom 挂载(mounted 之前)占用了很小的范畴,简直对白屏没有任何影响。重点关注两个阶段
- mounted -> playInit ready,即播放初始数据(playInit)筹备好之前
- playInit ready -> play,即拿到 playInit 到失常播放
这两个阶段加一起的耗时均匀靠近 2 秒,极其状况可能达到 4 – 5 秒。(统计日期 2021 年 12 月 28 日,此时有局部已做工作还没有实现)
拿到 playInit 之后就只有两个步骤,new Player(),执行 play() 办法,因而整个的流程图如下:
而后再看下 Chrome Performance 在 FP 之后的详情截图
有图中看出大工作别离是
- sessions 接口申请后的逻辑工作
- play/init 接口申请后的逻辑工作
- session_events 接口申请后的逻辑工作
- 执行 play 办法
网络申请耗时最长的是
- 事件流接口(session_events)
- 播放初始数据接口(play/init)
联合代码流程图和 Performance 截图,最初总结下以后存在问题:
- session_events 接口(事件流)以后为异步执行,有可能会呈现晚于视频播放的状况,不合乎产品需要
- session_events 接口自身存在数据耦合度太大导致下载工夫慢的问题(须要和后端沟通计划)
-
sessions 接口(会话列表)没必要做为前置条件,当初之所以前置是因为其余接口依赖 sessionId,但 获取 sessionId 和 sessions 接口其实没有强关联关系
- 内部进入状况下,能够间接从 url 参数获取 sessionId
- 外部切换的状况下,能够间接获取 sessionId
- session 接口(会话详情)在以后环境下只提供老版本视频资源 url,和 play/init 性能反复
- sources 接口和 paly/init 接口只依赖于 sessionId,没必要后置
- 拿到接口数据后的工作过大,耗时重大,因为播放前所有工作都必须执行结束,因而异步并不能解决问题
优化计划
- 干掉 session 接口(会话详情),资源 url 对立放到 paly/init 接口,缩小网络申请(须要后端配合)
- 并行执行 sessions、sources、session_events 和 paly/init 四个接口,缩小互相不必要的期待
-
session_events 接口变为两个
- 第一个只获取题目信息缩小资源下载工夫,另一个获取全量数据(须要反对分页),播放前只通过第一个接口,加载题目信息
- 第二个接口异步申请全副数据存储到内存,用户开展的时读取,如果用户点击开展的时候全量数据还没有返回,则依据点击项的索引分页申请对应的数据之后再开展,此时全量数据过去后须要有去重策略
- 应用 Web Worker 将拿到数据之后的耗时工作丢到子线程中,并行执行
-
调度工作 + 工夫切片
- 给不同的任务分配优先级,而后将一段长工作切片
- 尽量保障重要工作优先执行,其余工作或者无依赖关系工作主要执行(播放次要工作之外的其余工作)
- 事件流采纳虚构列表技术,缩小渲染耗费(不仅仅解决首次渲染问题,还解决后续滚动性能问题)
- 减少缓存,采纳 Service Worker 技术,缓存接口申请,谷歌的 Workbox 类库,以后版本只缓存 sources、paly/init 和 session_events 三个接口和局部动态资源,后续逐渐开展至全站缓存
ps:现阶段缓存曾经增加结束,产出 前端缓存机制晋升网站性能 – Service Worker
最终流程图