一、引言
在当今数字化时代,前端作为用户与网站或应用之间的直接交互界面,其性能优劣直接影响着用户的体验。随着网络技术的快速发展和用户对网页加载速度、交互流畅度要求的不断提高,前端性能优化已成为前端开发者必须关注的重要课题。
首先,前端性能优化对于提升用户体验至关重要。一个性能良好的前端页面能够迅速响应用户的操作,流畅地展示内容,使用户在浏览网页或使用应用时感到愉悦和便捷。相反,如果前端性能不佳,页面加载缓慢、交互卡顿,不仅会影响用户的使用体验,还可能导致用户流失,对网站或应用的运营产生负面影响。
其次,前端性能优化与用户体验之间存在着密切的关系。随着移动互联网的普及和智能终端的普及,用户对前端性能的要求越来越高。一个优秀的前端性能优化方案能够提升页面的加载速度、减少资源消耗、优化交互效果,从而提升用户的满意度和忠诚度。同时,通过优化前端性能,还可以降低服务器的负载压力,提高网站的稳定性和可靠性。
本文将从代码优化、构建优化、网络优化和渲染优化等方面探讨前端性能优化的关键领域,并介绍一些常用的性能优化工具和策略。
二、前端性能优化的关键领域
代码优化
-
懒加载
延迟加载(懒加载)是一种将资源标识为非阻塞(非关键)资源并仅在需要时加载它们的策略。这是一种缩短关键渲染路径长度的方法,可以缩短页面加载时间。
延迟加载可以在应用程序的不同时刻发生,但通常会在某些用户交互(例如滚动和导航)上发生。
js懒加载
import('./module.js').then(() => { // code })
资源懒加载
包括但不限于图片
、音视频
、字体
等
这里详细介绍一下图片,因为在大多数前端页面中,图片所占的比重最大。
前端主要使用到的图片格式包含以下几种:GIF
、JPG/JPEG
、PNG
、WEBP
格式 优点 缺点 场景 GIF 文件小,支持动画、透明,无兼容性问题 只支持256种颜色 色彩简单的logo、icon、动图 JPG 色彩丰富,文件小 有损压缩,反复保存图片质量下降明显 色彩丰富的图片/渐变图像 PNG 无损压缩,支持透明,简单图片尺寸小 不支持动画,色彩丰富的图片尺寸大 logo/icon/透明图 WEBP 文件小,支持有损和无损压缩,支持动画、透明 浏览器兼容性不好 支持webp格式的app和webview -
优先加载重要资源、推迟非关键 js 执行
默认情况下,JavaScript 的解析和执行会阻塞渲染。这意味着浏览器在遇到 JavaScript 之后,会阻塞解析任何出现在其后的 HTML 代码,直到脚本处理完成。因此,样式和绘制也会被阻塞。因此,你不仅需要仔细考虑你要下载的内容,还要考虑代码何时以及以何种方式执行。-
preload
预加载
在上面的代码中,当解析到script标签的时候,便会加载并执行main.js里面的代码,后面的解析就会被阻塞。可以使用preload对该js进行预取,然后再适当的时机进行执行。<head> <script src="/main.js"></script> </head>
预先加载的link会尽快获取js,而且不会阻塞渲染。然后你就可以在任意时机去使用了。<head> ... <!-- 预加载 JavaScript 文件 --> <link rel="preload" href="important-js.js" as="script" /> ... </head>
注意:预加载并不能保证脚本在你包含它时已经加载完成,但它确实意味着它将尽早开始下载。即使未完全移除阻塞渲染的时间,渲染阻塞时间仍将缩短。 - 推迟非关键代码获取和执行时机
script标签使用defer
和async
具体可以看:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/script
-
-
精简代码,减少冗余
这里不做过多赘述 -
优化事件性能
-
防抖
对于触发频率较高的事件进行防抖处理,比如:scroll
、mousemove
-
事件委托
减少要跟踪的事件监听器数量可以提高性能: 事件委托 -
清除无用的监听器
removeEventListener
-
-
使用
web-worker
Web Worker 为 Web 内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。此外,它们可以使用XMLHttpRequest
(尽管responseXML
和channel
属性总是为空)或fetch
(没有这些限制)执行 I/O。一旦创建,一个 worker 可以将消息发送到创建它的 JavaScript 代码,通过将消息发布到该代码指定的事件处理器(反之亦然)。
详情参考:Web Workers API -
js 动画操作
使用requestAnimationFrame
代替setInterval
。
构建优化
-
代码压缩
- js:uglify、terser
- css: MiniCssExtractPlugin
- html: HtmlWebpackPlugin
-
code spliting
为什么要用代码分割?当使用代码分割的时候- 通过代码分割,可以将应用程序拆分成多个更小的包,这些包可以并行下载,从而提高了页面加载的速度
- 在首次加载页面时,用户可能只需要访问某些特定的功能或模块。通过代码分割,可以将这些不立即需要的代码排除在首次加载的包之外,从而减少初始加载的资源量,提高用户体验
- 代码分割允许你实现按需加载(lazy loading)的功能。当用户触发某个特定的操作或访问某个特定的页面时,才加载相关的代码。这种方式可以有效地利用网络带宽,同时避免用户等待不必要的代码加载
- 由于每个代码块都是独立的,因此它们可以单独进行缓存。当某个代码块发生变化时,只有这个特定的块需要更新,而不会影响其他缓存的代码块。这有助于提高缓存效率,减少无效的资源请求。
-
tree-shaking
打包工具自带,不做赘述 -
dll
对于一些类库,比如:React、Vue,由于这些库的版本在开发中基本不会进行改变,可以通过dll进行打包,提升构建速度,也便于请求的时候进行缓存。 -
source-map
在生产环境一般不太需要source-map,所以打包的时候可以不添加source-map,提高打包速度,并且减少js代码的体积。如果需要在生产环境进行错误监控或者调试,请使用hidden-source-map
网络优化
-
缓存策略
- 强缓存
cache-control
、Expries
- 协商缓存
Etag/If-None-Match
、Last-Modified/If-Modified-Since
- 强缓存
-
gzip
压缩
nginx开启gziphttp { gzip on; gzip_buffers 32 4K; gzip_comp_level 6; gzip_min_length 100; gzip_types application/javascript text/css text/xml; gzip_disable "MSIE [1-6]\."; gzip_vary on; }
静态资源CDN
内容分发网络(CDN)是一组分布在多个不同地理位置的 Web 服务器。我们都知道,当服务器离用户越远时,延迟越高。CDN 就是为了解决这一问题,在多个位置部署服务器,让用户离服务器更近,从而缩短请求时间。-
http2
HTTP/2(原名HTTP/2.0)是下一代HTTP协议,相比HTTP/1.1,它提供了诸多优势。以下是HTTP/2的主要优点:多路复用(Multiplexing):HTTP/2允许通过一个单一的TCP连接同时传输多个请求和响应。这种特性显著提高了性能,因为它消除了HTTP/1.1中的队头阻塞问题,减少了网络延迟和请求等待时间。
二进制分帧(Binary Framing):HTTP/2将消息分割为更小的二进制编码的帧,这些帧可以在一个TCP连接中交错发送,然后再在另一端重新组装。这种方法减少了传输开销,提高了网络利用率,并且使得协议更加灵活和可扩展。
首部压缩(Header Compression):HTTP/2使用HPACK算法对头部信息进行压缩,这显著减少了传输的冗余数据,提高了传输效率。
服务端推送(Server Push):在HTTP/2中,服务端可以主动推送资源到客户端,而不需要等待客户端的显式请求。这有助于减少延迟,提升页面加载速度,因为服务端可以在客户端请求主资源的同时,推送与之相关的其他资源。
更好的流控制(Flow Control):HTTP/2提供了更精细的流控制机制,允许发送方和接收方调整数据发送的速度,从而避免网络拥塞和不必要的延迟。
提升用户体验:由于HTTP/2减少了请求等待时间和传输延迟,因此能够更快地加载页面和内容,从而提升用户体验。
需要注意的是,尽管HTTP/2具有这些显著的优势,但并非所有情况都适合使用它。例如,在小型或低频次的请求中,HTTP/2的优势可能并不明显。因此,在选择是否使用HTTP/2时,需要根据具体的应用场景和需求进行权衡。
nginx开启http2server { listen 443 ssl http2; server_name yourdomain.com; # SSL证书和私钥路径 ssl_certificate /path/to/your/ssl_certificate.crt; ssl_certificate_key /path/to/your/private.key; # 其他SSL配置选项(如ssl_protocols, ssl_ciphers等) # ... # 网站根目录和其他配置 # ... }
渲染优化
-
DOM操作
访问和更新 DOM 的计算成本很高,因此你应该尽量减少 JavaScript 这种操作方面的操作量。可以通过批量操作DOM或者虚拟DOM来解决该问题。当你有大量 HTML 代码要添加到页面时,先构建整个片段(通常在DocumentFragment
内部),然后一次性将其附加到 DOM 中,而不是逐个附加每个项目。 -
CSS操作
- 避免出现超过三层的嵌套规则
- 使用类选择器替代标签选择器
- 避免使用通配符选择器
- 避免重绘和回流
- 避免使用table布局:table布局在浏览器渲染时会导致多次回流,因此应尽量避免使用。可以使用CSS的flex或grid布局替代。
- 避免使用内联样式:直接在HTML元素中使用style属性设置样式会导致浏览器进行回流。应该尽可能使用CSS类名或ID来设置样式。
- 避免频繁操作DOM:对DOM的频繁操作(如添加、删除或修改元素)会触发回流。如果需要修改多个样式,可以使用classList.add()、classList.remove()或classList.toggle()等方法一次性修改多个类名,从而减少回流次数。
- 使用CSS3的transform和opacity:这两个属性不会引起回流,只会引起重绘。在需要进行动画效果时,应尽量使用这两个属性。
- 批量修改样式:如果需要对多个元素进行样式修改,可以考虑先将它们脱离文档流(例如使用documentFragment),修改完后再一次性添加回文档流,这样可以减少回流次数。
- 使用CSS的will-change属性:这个属性可以告诉浏览器哪些属性可能会改变,让浏览器提前准备,从而优化渲染性能。但是要注意不要滥用,因为过多的will-change可能导致浏览器进行不必要的优化工作。
三、前端性能优化工具
- 性能分析工具
浏览器内置的性能分析工具(如Chrome DevTools) - 第三方性能分析工具(如Lighthouse、WebPageTest等)
- 性能监控与报警
使用性能监控服务(如New Relic、Datadog等),设置性能阈值,实现性能报警
四、未来趋势与展望
WebAssembly
Wasm解决了JavaScript在运行效率上的缺陷。与传统的JavaScript相比,Wasm提供了更高的执行速度,因为它更接近硬件,能够更快地执行。Wasm的指令集包括基本指令和扩展指令,这种低级别的特性使其可以更好地利用现代多核CPU的并行处理能力,进一步提升了性能。
其次,Wasm的内存管理能力也为性能提升做出了贡献。Wasm提供了更细粒度的内存管理能力,允许开发者直接控制内存分配和回收。这种对内存的直接控制使得Wasm在处理大量数据或进行复杂计算时能够更有效地管理内存资源,从而提高性能。
再者,Wasm的语言多样性为前端开发带来了更大的灵活性。开发者不再受限于JavaScript,他们可以选择任何支持编译到Wasm的语言,如Rust、C、C++等。这使得开发者可以根据项目的实际需求选择最合适的语言,从而提高开发效率和应用性能。
Wasm的应用场景也非常广泛,包括游戏引擎、图像处理、音频处理等高性能计算场景。这些场景通常需要大量的计算和内存资源,而Wasm的高性能和细粒度的内存管理能力使其成为这些场景的理想选择。
此外,Wasm的设计和结构都是为了提供更高的性能。它的二进制格式紧凑,加载速度快,并发性高,这使得Wasm能够在现代浏览器中高效地运行。
WebGPU
https://developer.mozilla.org/zh-CN/docs/Web/API/WebGPU_API
WebGPU极大地提升了浏览器访问本地GPU的效率。传统的Web图形API,如WebGL,虽然能够利用GPU进行图形渲染,但在某些方面仍受到浏览器和JavaScript本身的性能限制。而WebGPU通过提供更接近底层GPU的访问,允许开发人员充分利用现代图形硬件的性能。这使得在前端实现复杂、高性能的3D图形应用成为可能,并且执行效率可以与本地程序相媲美。
如有错误或者建议,请指出,感谢~