昨天在开源圈发生个小插曲。起因是有个用户表示:React
新文档在文档结构、美观度、性能等各方面都达到很高的标准。
![6dd1ad7b45a81ddb8e6fc42591689b48.png](https://img-blog.csdnimg.cn/img_convert/6dd1ad7b45a81ddb8e6fc42591689b48.png)
尤雨溪对Vue
新文档与React Beta
文档做了测试后表示:在性能这块,Vue
新文档更具优势。
![364e6a49873793d811481d3f8da38f11.png](https://img-blog.csdnimg.cn/img_convert/364e6a49873793d811481d3f8da38f11.png)
Dan
表示:当前文档还处于Beta
版本,现在有更重要的工作要完成,正式版上线前会优化性能。
话虽这么说,Dan
应该是通了个宵优化了一把性能:
![f9af241c49c5f5d4d133acf385eaf972.png](https://img-blog.csdnimg.cn/img_convert/f9af241c49c5f5d4d133acf385eaf972.png)
本篇文章我们来看看,Dan
都做了哪些优化。
优化效果
经过优化后的lightHouse
跑分:
![af0030de20f195e4bb2fb2bfe932f87c.png](https://img-blog.csdnimg.cn/img_convert/af0030de20f195e4bb2fb2bfe932f87c.png)
作为对照,Vue
文档的跑分:
![e86746946e7cfb66c6c4e59915c85685.png](https://img-blog.csdnimg.cn/img_convert/e86746946e7cfb66c6c4e59915c85685.png)
两者10次TTI跑分对比:
![46754d827f30c925def4463124b0ee03.png](https://img-blog.csdnimg.cn/img_convert/46754d827f30c925def4463124b0ee03.png)
这里的TTI[1](Time to Interactive,即可交互时间),衡量的是「页面变得完全可交互所需时间」,其中「完全可交互」指:
页面展示了「有用信息」(由FCP衡量,FCP指First Contentful Paint)
可见页面中大部分元素完成事件绑定,交互响应的延迟在50ms内
优化措施
优化主要有两个思路:
编译时:减少打包体积
运行时:「非首屏必需」代码延迟加载
编译时优化
之前入口处全量引入了一个工具函数utils
,现在将其中方法拆分成不同文件,这样能减少首屏bundle
体积:
![f9a91860aa5c3b49af70aac3e0e8d4be.png](https://img-blog.csdnimg.cn/img_convert/f9a91860aa5c3b49af70aac3e0e8d4be.png)
再比如:
![c21859a786e9d7e37fdfaf7e78e3164f.png](https://img-blog.csdnimg.cn/img_convert/c21859a786e9d7e37fdfaf7e78e3164f.png)
这部分优化让bundle
体积减少约一半:
![e5ddaaa412f39bf6221a8806a669eb93.png](https://img-blog.csdnimg.cn/img_convert/e5ddaaa412f39bf6221a8806a669eb93.png)
其次,当前Next.html" title=js>js
(文档使用的框架)没有默认开启「针对现代浏览器编译」。这意味着bundle
中会引入更多polyfill
,有更多语法转换及帮助函数。
Dan
通过配置开启了这个功能:
![df6776e97cb57e62c13907e8a50ae3a5.png](https://img-blog.csdnimg.cn/img_convert/df6776e97cb57e62c13907e8a50ae3a5.png)
运行时优化
运行时优化的方式主要是:懒加载非必需资源。
新文档中存在很多codesandbox
(在线示例),这些示例依赖CodeMirror linter
,但这不是首屏必需的。
所以Dan
将这部分资源懒加载:
![27d6fec836b66b990d36db8863cfcebb.png](https://img-blog.csdnimg.cn/img_convert/27d6fec836b66b990d36db8863cfcebb.png)
除此之外,如果你细心观察会发现,Total Blocking Time
指标下降很多:
![11941bb6f8dcbf3da62d248894724e33.png](https://img-blog.csdnimg.cn/img_convert/11941bb6f8dcbf3da62d248894724e33.png)
TBT[2](Total Blocking Time
,即总阻塞时间)测量页面「被阻止响应用户输入(例如鼠标点击、屏幕点击或按下键盘)的总时间」。
一般来说,如果JS
执行时间过长,就会影响这个指标。
我们知道,页面加载后前端框架会有首屏渲染
的初始化过程。即使是服务端渲染,也会有Hydrate
(注水)的过程。
而React18
的Selective Hydration
为解决这一问题提供了好方法。
如果你的React18
应用是SSR
,那么被<Suspense/>
包裹的组件部分不会参与首次Hydrate
的过程。
也就是说,被<Suspense/>
包裹的部分不会影响阻塞时间。
所以,虽然这部分工作很重要,但Dan
需要做的,仅仅是把一些「对首屏显示不太重要的组件」包裹在<Suspense/>
中。
可以看到,在将一些组件用<Suspense/>
包裹前Hydrate
作为一个长任务的耗时:
![454535f4fb8841b634e0f831d9de51ba.png](https://img-blog.csdnimg.cn/img_convert/454535f4fb8841b634e0f831d9de51ba.png)
当包裹之后,这个长任务持续时间显著降低,进而降低TBT
:
![29378705441e4dab2081d138444c1829.png](https://img-blog.csdnimg.cn/img_convert/29378705441e4dab2081d138444c1829.png)
总结
这些只是初步的优化结果,后续还有很多优化工作值得去做。比如INP[3](Interaction to Next Paint,与下一次Paint的交互)指标还是偏高:
![b47fb38ed7cba8159ac06efe2724481a.png](https://img-blog.csdnimg.cn/img_convert/b47fb38ed7cba8159ac06efe2724481a.png)
Dan
坦言:指标偏高的原因可能是因为 —— React
本身比较慢。
他对此提出了一些猜想,你可以到这里参与讨论[4]。
参考资料
[1]
TTI: https://web.dev/tti/
[2]TBT: https://web.dev/tbt/
[3]INP: https://web.dev/inp/
[4]参与讨论: https://github.com/reacthtml" title=js>js/reacthtml" title=js>js.org/issues/4691
彦祖,亦菲,点个「在看」吧