Web前端性能优化思路

本文旨在整理常见web前端性能优化的思路,可供前端开发参考。因为力求精简,限于篇幅,所以并未详述具体实施方案。
基于现代web前端框架的应用,其原理是通过浏览器向服务器发送网络请求,获取必要的index.html和打包好的js、css等资源,在浏览器内执行js,动态获取数据并渲染页面,从而将结果呈现给用户。
在这个过程中,有两个步骤可能较为耗时,一个是网络资源的加载,另一个是浏览器内代码执行和dom渲染。
而耗时的增加会导致页面响应慢,卡顿,影响用户体验。
针对上述两种耗时的情况,常见的优化方向有:
缩短请求耗时; 减少重排重绘; 改善js性能。 1 缩短请求耗时 网络资源是web应用运行的基础,改善网络资源加载速度会显著改善前端性能。
1.1 优化打包资源 总体原则: 减少或延迟模块引用,以减少网络负荷。
常用工具:
webpack webpack-bundle-analyzer可视化分析工具 常用方法:
减小体积:减少非必要的import;压缩js代码;配置服务器gzip等;使用webp图片; 按需加载:可根据“路由”、“是否可见”按需加载js代码,减少初次加载js体积。比如可以使用import()进行代码分割,按需加载; 分开打包:利用浏览器缓存机制,依据模块更新频率分层打包。 其他方法:
雪碧图:每个http/1.1请求都是独立的tcp连接,最大6个并发,所以合并图片资源可以优化加载速度。http/2已经不需要这么做了。 1.2 cdn加速 总体原则: 通过分布式的边缘网络节点,缩短资源到终端用户的访问延迟。
常用工具:
cloudflare aws cloudfront aliyun cdn 常用方法:
加速图片、视频等大体积文件 1.3 浏览器缓存 总体原则:避免重复传输相同的数据,节省网络带宽,加速资源获取。
常用方法:
可以通过设置http header来控制缓存策略,一般有如下几种。
强缓存
expires:http/1.0 cache-control:http/1.1 协商缓存
etag + if-none-match last-modified + if-modified-since 拿etag举例,如果浏览器给的if-none-match值与服务端给的etag值相等,服务器就直接返回304,从而避免重复传输数据。
etag示例:
如果几个配置同时存在,则优先级为:cache-control > expires > etag > last-modified。
1.4 更高版本的http 总体原则:使用高版本http提升性能。
常用工具:
http/2 http/2较http/1.1最大的改进在于:
多路复用:单一tcp连接,多http请求,有demo; 头部压缩:减少http头体积; 请求优先级:优先获取重要的数据; 服务端推送:主动推送css等静态资源。 其他方法:
http/3 http/3基于udp,有很多方面的性能改进,如多路复用无队头阻塞,响应更快。感兴趣的同学可参考wiki。
1.5 web socket 总体原则:解决http协议无法实时通信的问题。
web socket是一条有状态的tcp长连接,用于实现实时通信、实时响应。
1.6 服务器端渲染(ssr) 总体原则:第一次访问时,服务器端直接返回渲染好的页面。
一般流程:
浏览器向 url 发送请求; 服务器端返回“空白”index.html; 浏览器不能呈现页面,需要继续下载依赖; 加载所有脚本后,组件才能被渲染。 ssr流程:
浏览器向 url 发送请求; 服务器端执行js完成首屏渲染并返回; 浏览器直接呈现页面,然后继续下载其他依赖; 加载所有脚本后,组件将再次在客户端呈现。它将对现有view进行合并。 常用工具:
node.js,用于服务器端执行代码,输出html给浏览器,支持所有主流前端框架 next.js,用于服务器端渲染react的框架 gatsby,用react生成静态网站的工具 除了可以提升页面用户体验,还能应用于seo。
2 减少重排重绘 除了网络资源以外,另一个影响前端性能的因素就是前端页面的渲染绘制效率。
虽然不同的前端框架有一些差异,但整体的优化思路是一致的,这里将以react举例。
2.1 减少渲染量 总体原则:不渲染未展示的部分。
常用工具:
react-window react-loadable js原生,如intersectionobserver 框架提供,如react.lazy、react-intersection-observer 常用方法:
虚拟列表:只渲染可见区; 惰性加载:无限滚动; 按需加载:页面只在切换过去时才加载。 以虚拟列表举例,以下是使用react-window库,仅仅渲染了可见区的数据:
2.2 减少渲染次数 总体思路:避免重复的渲染。
常用工具:
lodash js或框架自带 常用方法:
防抖与节流; 对于react函数组件来说,合理使用副作用,拆分无关联的副作用; 对于react类组件来说,可以使用shouldcomponentupdate或使用purecomponent来优化渲染; 利用缓存,如react.memo; 使用requestanimationframe替代setinterval执行动画。 3 改善js性能 因为浏览器是单线程异步模型,长时间的运算会阻塞渲染过程,所以改善复杂运算有助于改善前端的整体性能。
3.1 缓存复杂计算 总体思路:避免重复计算。
常用方法:
对于react函数组件来说,可以使用usememo缓存复杂计算值。 举例如下,memoizedvalue需要经过复杂计算才能得到,此时就可以使用usememo缓存,仅仅在输入参数发生变化时才重新计算,避免计算阻塞页面渲染,从而避免页面卡顿。
1const myfunctionalcomponent = () => {2 const memoizedvalue = usememo(() => {3 computeexpensivevalue(a, b);4 }, [a, b]);56 return ;7} 但usememo自身也有性能消耗,需要视情况使用,某些场景可以利用react的渲染机制避免性能问题,可以参考《before you memo()》。
3.2 web worker 总体原则:多线程思想。
常用方法:
dedicated workers,处理与ui无关的密集型数学计算:大数据集合排序、数据压缩、音视频处理; service worker,服务端推送,或者pwa中配合cachestorage在前端控制缓存资源; shared worker,tab间通信。 js语言在设计之初就是单线程异步模型,好处是可以高效处理i/o操作,但坏处是无法利用多核cpu。
web worker会启动系统级别的线程,可进行多线程编程,发挥多核的性能。
3.3 web assembly 总体原则:将复杂的计算逻辑编译为web assembly,避免js类型推断过程中的性能开销,可用于性能的极限优化。
适用范围有限:
曾在网上看到,有人使用自顶向下非优化的斐波那契数列算法来举例,说web assembly比原生js快一倍,实测之后似乎也没有。
在同一台机器测试,其中求第48个值的耗时如下:
c(ubuntu+gcc):18s js(v8):32s web assembly(v8+emcc):39s 一种可能的猜想是,斐波那契计算中没有大量的类型推断,而且v8内部有一些优化机制,使得此处js执行速度快于web assembly。
简而言之,并非所有场景都适用于web assembly。
另一种运用场景是,把不同语言编写的代码(c/c++/java等)编译为web assembly,能以接近原生的速度在web中运行,并且与js共存。
总结 导致前端性能问题的因素是多方面的。
如果是前端资源加载慢,导致页面慢,则应该考虑如何缩短请求耗时。而如果是前端页面逻辑笨重,ui数据量太大,则可以试着从减少重排重绘的角度去优化。对于耗时长的复杂计算,缓存计算结果往往是见效较快的优化方式。
最后需要注意的是,在实际应用开发过程中,因为受限于开发成本,所以需要平衡优化所花的代价与其对应产生的成效。可以有针对性地对性能瓶颈进行分析和处理,同时也需要避免引入不必要的优化措施,以确保最终优化效果。

2020年10月国内手机市场运行分析报告
DSEP60-12A/STTH6012快恢复二极管的基础资料
各类传感器知识的入门介绍
华为表示并没有推迟和减产手机的产量
全球晶圆代工厂排名
Web前端性能优化思路
桶外搅拌混合器搅拌流场仿真分析
由负-12V电源获得3.3V输出的电路
你知道人体识别吗,ReID技术了解一下
佐治亚理工大学开发出,诱饵机器人,当黑客侵犯时,它可诱骗对方
Kohls合作Snapchat AR推假日AR快闪和黑五AR促销活动
上汽通用交付具备自动泊车系统的量产车
华为运动健康,十年创新天地宽
Hubi2019年开启新的布局与规划,深耕数字货币交易所领域
用三极管实现一种信号的2个LED指示灯状态显示电路
相同的液晶面板 液晶电视差价为何这么大
关于智能化指纹锁四大性能参数的详细说明
微软最近就收购GitHub进行了谈判,该公司的收购价格可能高达50亿美元
全球170个国家/地区移动连接指数排名
易华录亮相2023信息技术应用创新论坛