前端面试题(十)
51. 前端性能优化
在前端开发中,性能优化是面试中的一个常见话题。面试官通常会希望候选人具备识别性能瓶颈并提出相应解决方案的能力。以下是一些常见的前端性能优化面试题及其答案。
1. 前端性能优化有哪些常见手段?
前端性能优化的手段可以从多个维度考虑,主要包括:
-
减少 HTTP 请求:
- 合并 CSS、JavaScript 文件,使用雪碧图(sprite images),减少页面加载时的请求数量。
- 使用 HTTP/2 以实现多路复用,提高请求效率。
-
资源压缩与优化:
- 使用工具压缩 HTML、CSS、JavaScript 文件,例如使用 UglifyJS 压缩 JavaScript,使用 CSSNano 压缩 CSS。
- 对图片进行无损压缩,使用现代格式如 WebP。
- 延迟加载非关键资源,例如延迟加载图片(Lazy Load)。
-
使用缓存:
- 合理配置缓存策略,使用
Cache-Control
和Expires
头。 - 使用 Service Worker 来实现离线缓存和资源预取。
- 合理配置缓存策略,使用
-
异步加载资源:
- 使用
async
和defer
来异步加载 JavaScript 文件,防止阻塞页面的渲染。 - 将 CSS 文件放在
<head>
中,确保尽早加载,JavaScript 文件放在<body>
底部,避免阻塞 HTML 渲染。
- 使用
-
DOM 操作优化:
- 减少 DOM 操作,批量更新 DOM,避免频繁触发回流和重绘。
- 使用文档片段(Document Fragment)或虚拟 DOM 来减少操作真实 DOM 的次数。
-
提高首屏加载速度:
- 通过服务器端渲染(SSR)加快首屏渲染时间。
- 使用懒加载和按需加载技术,只加载用户可视区域的资源。
-
CDN 加速:
- 使用内容分发网络(CDN)加快静态资源的分发,减少服务器压力,缩短资源传输的物理距离。
2. 什么是回流 (Reflow) 和重绘 (Repaint)?如何避免?
- 回流 (Reflow):当页面的布局、大小、位置或几何属性发生变化时,浏览器需要重新计算元素的布局。回流是一个非常耗时的过程,尤其当涉及到大量元素时,性能会显著下降。
- 重绘 (Repaint):当页面元素的外观(如颜色、边框等)发生变化时,浏览器会重新绘制这些元素,但不影响布局,这个过程比回流更轻量。
避免回流和重绘的方法:
- 合理使用 CSS:避免频繁操作影响布局的属性,如
width
、height
、padding
、border
等。 - 减少 DOM 的操作:尽量批量更新 DOM,使用文档片段或一次性修改多个属性。
- 使用
visibility: hidden
代替display: none
:display: none
会触发回流,而visibility
只会触发重绘。 - 避免频繁读取导致回流的属性,如
offsetTop
、offsetHeight
等。可以将这些值缓存起来,减少读取次数。
3. 如何提升网站的首屏加载速度?
-
压缩与合并资源:
- 对 HTML、CSS、JavaScript 进行压缩,减少文件体积。
- 合并多个 CSS、JavaScript 文件,减少 HTTP 请求。
-
CDN 加速:
- 使用 CDN 将静态资源部署到离用户最近的节点,减少资源的下载时间。
-
懒加载与按需加载:
- 对非首屏的图片、视频、脚本等资源进行懒加载,只在用户需要时加载这些资源。
-
预加载关键资源:
- 使用
<link rel="preload">
提前加载关键资源,如字体、样式表和重要的脚本,确保它们尽快生效。
- 使用
-
服务端渲染 (SSR):
- 使用服务端渲染将页面 HTML 预生成,减少浏览器解析时间,加快首屏展示速度。
-
Critical CSS:
- 把关键的 CSS 样式内联到 HTML 中,减少渲染阻塞,同时推迟加载其他非关键的 CSS 文件。
-
减少第三方库和插件:
- 尽量减少使用庞大的第三方库和插件,例如可以选择体积更小的库代替 jQuery 或者 Lodash,避免引入不必要的功能。
4. 什么是 Webpack?如何使用 Webpack 优化前端性能?
Webpack 是一个模块打包工具,它可以将项目中的各种资源(JavaScript、CSS、图片等)视作模块,并打包成可供浏览器运行的静态文件。
使用 Webpack 进行前端性能优化的方式有:
-
代码拆分 (Code Splitting):
- Webpack 提供了代码拆分功能,可以将应用程序分割成多个较小的包,按需加载不同部分的代码,从而减少初始包的大小,提升页面加载速度。
- 例如通过
import()
实现动态导入:import('./module').then(module => { // 模块加载完成后执行 });
-
Tree Shaking:
- Webpack 的 Tree Shaking 能够在打包时移除未使用的代码,这对于优化大型项目的包大小非常有效。确保使用 ES6 的模块系统 (
import/export
) 来支持 Tree Shaking。
- Webpack 的 Tree Shaking 能够在打包时移除未使用的代码,这对于优化大型项目的包大小非常有效。确保使用 ES6 的模块系统 (
-
文件压缩:
- 使用 Webpack 的
TerserPlugin
对 JavaScript 进行压缩,减少文件体积。 - 对 CSS 使用
css-minimizer-webpack-plugin
进行压缩。
- 使用 Webpack 的
-
图片优化:
- 使用 Webpack 的
image-webpack-loader
插件自动压缩图片,生成适合网络传输的小体积图片。
- 使用 Webpack 的
-
缓存策略:
- Webpack 生成带有内容哈希的文件名,保证每次代码更新时文件名会变动,确保浏览器能够获取最新版本的资源。同时未变动的文件则可以通过缓存策略长期缓存,减少不必要的网络请求。
5. 为什么说 HTTP/2 有助于前端性能提升?
HTTP/2 相较于 HTTP/1.1 有多项改进,有助于提升前端性能:
- 多路复用 (Multiplexing):HTTP/2 允许在同一个 TCP 连接上并行处理多个请求和响应,解决了 HTTP/1.1 中的队头阻塞问题,大大提高了传输效率。
- 头部压缩 (Header Compression):HTTP/2 使用 HPACK 算法对请求和响应的头部进行压缩,减少了数据传输的体积,尤其对那些拥有大量重复头部信息的请求非常有效。
- 服务器推送 (Server Push):服务器可以在客户端请求前主动发送资源,减少客户端请求的等待时间。比如在用户请求一个 HTML 页面时,服务器可以提前推送该页面需要的 CSS 和 JavaScript 资源。
- 优先级控制 (Stream Prioritization):HTTP/2 允许客户端为请求分配优先级,服务器可以根据优先级安排资源的传输顺序,确保关键资源优先加载。
6. 如何通过减少 DOM 操作来优化性能?
频繁的 DOM 操作会触发回流和重绘,影响页面的性能。以下是减少 DOM 操作的几种常见方式:
- 使用虚拟 DOM:像 React 和 Vue 等框架使用虚拟 DOM,可以减少直接操作真实 DOM 的次数,提高渲染性能。
- 批量操作 DOM:将多次操作合并成一次,例如使用文档片段(Document Fragment)进行批量操作,然后一次性插入 DOM。
- 缓存 DOM 元素:避免多次查询相同的 DOM 元素,可以将查询结果缓存起来,减少重复的 DOM 查询操作。
- 减少频繁修改样式:一次性修改元素的多个样式属性,而不是每次操作都触发重绘。
- 避免读取会触发回流的属性:避免频繁读取
offsetTop
、offsetHeight
等会触发回流的属性,可以通过将这些值缓存起来减少读取次数。