一直以来,前端性能优化都是面试过程中考察的热点题目。
相关的技术博客也层不出穷,我们总是能找到很多这样的文章,
从一个应用的各个层面开始分析,优化的种种手段,取得的种种效果。
往往篇幅越长,讲得越细,越受欢迎。
但在面试的时候,问这类问题时,候选人经常答得不尽人意,大部分人会把自己能想起来的优化措施,给背一遍。
背得越多越好,对于候选人自己说,内心也发虚,背完之后面试官毫无表情,因为这并不是他们想要的答案。
我们不妨从面试官的角度来思考。
面试官想考察什么?
- 这个很容易考察候选人技术的宽度和广度。
- - 可以从网络层面,打包层面,渲染层面问你对前端知识边界的了解。 - 也可以就一个方面深入考察,比如http2,tcp的队头阻塞问题,webpack分包策略等等。
- 考察一个人做事的能力和思考的方式。
- - 如果真的做过,那么是如何实施的,怎么和其他部门配合的,遇到了哪些问题,怎么解决的。 - 如果没做过,那么会怎么来计划,推进这件事情。
- 不至于让候选人无话可说。
- - 面试过程中很容易陷入一种,面试官问不出问题,候选人答不出问题的尴尬境地,这种性能优化的问题就可以让双方都有话可说。
当然,面试是门玄学,实际在面试过程中,根据面试官的状态,技术问题的侧重点也是不一样的。
那么作为候选人来说,如何回答,才能脱颖而出呢?
候选人如何回答?
首先第一个疑问就是,做过没做过呗?
如实回答即可,做过就讲自己做的过程,没做过就讲自己准备怎么做。
大的原则就是:稍带广度,突出深度。
两种情况我们需要分类讨论。
如果做过
或者你要假装自己做过。
明确范围
那就要明确你要进行前端优化的场景范围,或者说是要优化的应用是哪个种类。
- 一个toC的纯H5,在浏览器和微信里使用
- 一个toB的系统,或者说内部使用的运营系统
- 嵌入app内使用的Hybrid
- 公司官网
- 跨端应用,小程序等等
以上每种类别优化的方式都是要根据场景采用的措施和手段是不一样的。
在回答的过程中,要明确这个基础。
比如说,对于一个离线加载的h5,应当从网络层面突出强调离线加载的好处,而不是说资源体积上的优化。
明确目标
性能优化需要目标,这个目标肯定是一个量化数据。
这就考察到了候选人对前端页面性能数据的掌握。
比如常问题目,你们在优化过程中,是如何制定目标,或者说如何排查阻塞问题的?
这个问题其实是在问你们如何采集页面数据。
性能数据采集分为两种
- 实验室性能数据采集
- - google的lightHouse 帮助我们分析页面的六大属性 - First contentful paint 首次内容绘制 (FCP) - Largest contentful paint 最大内容绘制 (LCP) - First input delay 首次输入延迟 (FID) - Time to Interactive 可交互时间 (TTI) - Total blocking time 总阻塞时间 (TBT) - Cumulative layout shift 累积布局偏移 (CLS)
- - 谷歌浏览器的性能面板,做具体链路阻塞的分析。
- 线上真实数据采集
- - 线上接入入web-vitals做用户的数据收集 - 接入sentry等一些三方SDK做性能数据的收集
确定方案
在分析整个前端页面性能优化的链路过程中,我们需要找到一个阻塞点,或者说切入点。
以一个app中webview中嵌套h5的场景来说
我们需要找到从用户点击跳转开始,到展现的过程中,经历了哪几个阶段,哪个阶段耗时多久,成为了阻塞页面的主要问题,然后针对问题再说实施了哪些优化。
比如下面这个问题,用户反馈APP内打开H5页面白屏时间过长,你应该怎么处理?
我们不能回答是用户网络不好吧。
针对这个问题,也有优化方式:
- 针对 WebView 初始化: 当客户端刚启动时,可以先提前初始化一个全局的 WebView 待用并隐藏
- 针对向后端发送接口请求:在客户端初始化 WebView 的同时,直接由 Native 开始网络请求数据,当页面初始化完成后,向 Native 获取其代理请求的数据。
- 针对加载的 js 动态拼接 html(单页面应用):可采用多页面打包, 服务端渲染,以及构建时预渲染等方式。
- 针对加载页面资源的大小:可采用懒加载等方式,将需要较大资源的部分分离出来,等整体页面渲染完成后再异步请求分离出来的资源,以提升整体页面加载速度。
当然我只是举个例子,在回答的过程中还是要突出重点,
如果对网络掌握较好,就说网络层面优化,
如果对打包工具熟悉,就说体积层面优化,
如果对浏览器熟悉,就说渲染层面的优化,
如果你对三方面都熟悉,那么应该不会看这篇文章。
如果没做过
如果没做过,但肯定了解过吧。
如果不了解,看完这篇文章吧。
主要从三个方面回答
传输
- 使用CDN,对静态资源进行缓存。
- - 那么CDN回源和预热是什么回事? - 使用CDN和不使用CDN有什么区别? - 如何判断当前资源命中了CDN? - 你们项目中如何使用CDN的。
- 使用http2,多路复用的特性,头部压缩,请求优先级
- - http2 是怎么解决http1.1的头部阻塞问题的? - http2 彻底解决了队头阻塞问题了吗?他还有哪些问题? - nginx如何配置使之生效 - http3 有了解吗?
- 充分利用浏览器缓存策略
- - 强缓存和协商缓存的区别 - nginx中应该如何配置缓存字段 - 分包加载,如何避免一行代码修改导致整个 bundle 的缓存失效
体积
- 开启gzip压缩,对文本资源处理
- - 除了gzip压缩,还有哪些压缩方案 - 如何配置gzip压缩
- 压缩JS资源
- - 如何压缩js资源,有哪些库。 - 压缩后的代码和未压缩之前有什么区别 - sourcemap线上环境,测试环境,本地环境有什么区别
- 图片大小的优化
- - 使用webp格式替换原有的png/jepg
- 三方库的按需加载,按需打包
- - 编译代码中,如何支持tree-shaking? - 没有按需打包之前,有什么问题?
渲染
要说渲染呢,就要理解渲染过程,我们的前端代码如何在浏览器中展示出来的。
- 从html解析成DOM树
- 从CSS解析成CSS树
- 结合DOM树木和CSS树,合并渲染树
- 根据渲染树,确定DOM 树的位置布局信息
- 然后再将每个节点渲染在浏览器中
所以需要减少渲染的次数,也就是我们所说的重绘,重排
加快html和css 的解析速度。
其实这能展开说的点就很多了,需要结合具体场景去分析。
- 对关键资源的预加载,对非关键资源的延后加载
- - preload 和 prefecth 的使用区别 - async 和 defer 的使用区别 - dns-prefetch 对域名做预解析的作用
- 请求的缓存,避免短期内切换页面反复请求接口
- - 缓存在哪里,你知道有哪些缓存方式,应该使用哪种缓存方式
- 防抖和节流,减少渲染次数。
- - 解释一下防抖节流的使用场景 - 要不,来手写个防抖函数
最后
其实我在文章中,也没有说任何题目的答案。
只是提供了一条思路,顺着性能优化这条思路,我们可以去学习计算机网路方面的知识,浏览器缓存方面,nginx配置方面,webpack的分包策略,页面解析渲染方面,图片优化方面,离线加载方面的知识。
这道题想要答得出彩,应当还是找到一两个方面深入研究。
如果觉得我这篇文章写得还不错的话,
欢迎关注我的公众号:天涯碧草话斜阳,
直接搜索即可添加,我会写原创的前端文章,职场生活和成长思考。
上面有我的联系方式,如果愿意的话,可以交个朋友。
我们共同进步,一起加油!