1、频繁变动资源」:设置Cache-Control:no-cache,使浏览器每次都发送请求到服务器,配合Last-Modified/ETag验证资源是否有效 「不常变化资源」:设置Cache-Control:max-age=31536000,对文件名哈希处理,当代码修改后生成新的文件名,当HTML文件引入文件名发生改变才会下载最新文件 具体是哪些文件?
2、「加载优化」:资源在加载时可做的性能优化 「执行优化」:资源在执行时可做的性能优化 「渲染优化」:资源在渲染时可做的性能优化 「样式优化」:样式在编码时可做的性能优化 「脚本优化」:脚本在编码时可做的性能优化 「V8引擎优化」:针对V8引擎特征可做的性能优化 具体是哪些?
一、「加载优化」:资源加载时的性能优化
核心目标:减少资源加载时间、降低请求开销、优先加载关键资源。
-
资源压缩与合并
- 压缩:JS 用 Terser,CSS 用 CSSNano,HTML 用 html-minifier;图片用 WebP/AVIF 格式(比 JPEG 小 30%+),非透明图优先 WebP,透明图用 PNG8 或 WebP。
- 合并:小图标合并为 Sprite 图(减少请求),非关键 JS/CSS 按需合并(避免过大单文件)。
-
合理使用缓存
- 静态资源(CSS/JS/ 图片):
Cache-Control: max-age=31536000+ 文件名哈希(如app.xxx.js)。 - 频繁变动资源(HTML/API 数据):
no-cache+Last-Modified/ETag验证。
- 静态资源(CSS/JS/ 图片):
-
延迟与异步加载
- 非关键 JS:用
async(加载完立即执行,顺序无关)或defer(DOM 解析完执行,按顺序)。 - 图片 / 视频:懒加载(
loading="lazy"属性,或监听IntersectionObserver),优先加载可视区资源。 - 组件懒加载:路由级拆分(如 React.lazy+Suspense,Vue 异步组件)。
- 非关键 JS:用
-
CDN 与资源分发
- 静态资源部署到 CDN(利用边缘节点缓存,减少跨地域延迟)。
- 大文件分片加载(如视频用 HLS/DASH 协议,分成小片段按需加载)。
-
减少请求开销
- 启用 HTTP/2(多路复用,减少连接建立成本)或 HTTP/3(QUIC 协议,抗丢包)。
- 减少 Cookie 体积(静态资源域名与主域名分离,避免不必要的 Cookie 携带)。
-
**优化加载顺序
- 预加载关键资源:使用
<link rel="preload">强制浏览器优先下载关键资源(如关键CSS、Web字体)。 - 懒加载非关键资源:使用
loading="lazy"延迟加载视口外的图片和 iframe。 - 异步加载脚本:使用
async或defer属性,避免 JS 阻塞 HTML 解析。
- 预加载关键资源:使用
二、「执行优化」:资源执行时的性能优化
核心目标:减少 JS/CSS 执行时间,避免主线程阻塞。
-
JS 执行优化
-
避免长任务(执行时间 > 50ms):将复杂逻辑拆分为微任务(
Promise)或宏任务(setTimeout),利用 Web Worker 处理计算密集型操作(如数据解析、图表渲染)。 -
优化循环与递归:减少循环嵌套(如 O (n²)→O (n)),递归改为迭代(避免栈溢出),使用
break/continue提前退出无效循环。 -
减少 DOM 操作频率:批量修改 DOM(先脱离文档流,如
documentFragment,修改后再插入)。 -
使用 Web Workers 将纯计算密集型任务(如图像处理、数据解析)放到 Worker 中,避免阻塞 UI 线程。
-
优化事件处理 : 防抖(Debounce)和节流(Throttle) :控制
resize、scroll、input等高频事件的触发频率。 -
事件委托:利用事件冒泡,将事件监听器绑定在父元素上,减少内存占用和绑定数量。
-
-
CSS 执行优化
- 避免复杂选择器:减少嵌套层级(如
div:nth-child(2) > .class ~ span改为扁平类名),浏览器匹配选择器是从右向左,复杂选择器计算耗时。 - 减少
@import:@import会阻塞后续 CSS 解析,改用<link>并行加载。
- 避免复杂选择器:减少嵌套层级(如
三、「渲染优化」:资源渲染时的性能优化
核心目标:减少回流(重排)、重绘,提升渲染流畅度。
-
减少回流与重绘
- 批量修改样式:用
class一次性切换样式,而非逐个修改style属性。 - 避免触发回流的属性:读取
offsetWidth、scrollTop等布局属性后立即修改样式(会导致浏览器强制同步布局),应先集中读取,再集中修改。 - 使用
will-change或transform:将频繁动画元素设为will-change: transform,动画用transform(仅触发合成层,无回流)而非top/left。
- 批量修改样式:用
-
优化渲染树
- 移除无效 DOM:删除隐藏元素(
display: none)或冗余节点(如空<div>),减少渲染树规模。 - 合理使用
visibility: hidden与display: none:前者保留布局(重绘不回流),后者不保留(回流),按需选择。
- 移除无效 DOM:删除隐藏元素(
-
合成层优化
- 避免过多合成层:每个合成层占用内存,过多会导致卡顿(如大量
transform: translateZ(0)滥用)。 - 大图片 / 视频用
object-fit:避免缩放导致的合成层重计算。
- 避免过多合成层:每个合成层占用内存,过多会导致卡顿(如大量
-
使用 CSS3 硬件加速
- 对动画元素使用 `transform` 和 `opacity` 属性。这些属性由合成器处理,不涉及主线程和重排/重绘。
- 可以触发硬件加速的属性:`transform`, `opacity`, `filter`, `will-change`。
-
优化动画
- 优先使用 CSS 动画(
animation)和过渡(transition),而非 JavaScript 控制的动画。
- 优先使用 CSS 动画(
四、样式优化
核心目标:编写高效、可维护的 CSS。
-
选择器性能
- 避免使用过于复杂的选择器(如
.nav ul li a),保持简洁。 - 避免使用通配符
*和深层级选择器。
- 避免使用过于复杂的选择器(如
-
避免使用昂贵的属性
- 某些属性(如
box-shadow、border-radius、filter)在绘制时计算成本较高,应谨慎使用,尤其是在需要动画的元素上。
- 某些属性(如
-
使用 Flexbox 或 Grid 布局
- 现代布局方案(Flexbox、Grid)的性能通常优于传统的 Float 或 Table 布局。
-
内联关键 CSS
- 将首屏渲染所需的关键样式通过
<style>标签内联在 HTML 的<head>中,减少首次渲染的 RTT。
- 将首屏渲染所需的关键样式通过
五、「脚本优化」:脚本编码时的性能优化
核心目标:提升 JS 执行效率,减少内存占用。
-
变量与函数优化
- 减少全局变量:全局变量常驻内存,优先用局部变量(作用域链短,访问快)。
- 函数防抖(Debounce)与节流(Throttle):高频事件(resize、scroll、input)用防抖(如搜索输入)或节流(如滚动加载)限制执行频率。
-
数据处理优化
- 用
Map/Set替代对象 / 数组:查找效率更高(Map.get为 O (1),数组indexOf为 O (n))。 - 避免不必要的数据复制:大数组用
slice(浅拷贝)而非JSON.parse(JSON.stringify())(深拷贝耗时),必要时用结构化克隆(structuredClone)。
- 用
-
事件处理优化
- 事件委托:父元素代理子元素事件(如列表项点击,绑定到
<ul>),减少事件监听器数量。 - 及时解绑事件:组件卸载时移除
addEventListener绑定,避免内存泄漏。
- 事件委托:父元素代理子元素事件(如列表项点击,绑定到
-
DOM 操作优化
- 批量修改 DOM:使用
DocumentFragment或在离线 DOM 上操作,最后一次性插入文档。 - 减少对 DOM 的查询:将查询结果缓存起来。
- 批量修改 DOM:使用
-
流程控制优化
- 在循环中,
for循环通常比forEach等函数式方法更快。 - 使用
switch代替多个if-else。
- 在循环中,
六、「V8 引擎优化」:针对 V8 特征的优化
V8 是 Chrome/Node.js 的 JS 引擎,优化需贴合其编译(JIT)和内存管理机制。
-
类型稳定化
- 避免同一变量频繁切换类型:V8 会为对象创建隐藏类(Hidden Class),类型突变会导致隐藏类重建,降低执行效率(如
let a = 1; a = "str")。 - 数组元素类型统一:纯数字数组(
[1,2,3])比混合类型数组([1, "a", {}])更高效,V8 会优化为连续内存存储。
- 避免同一变量频繁切换类型:V8 会为对象创建隐藏类(Hidden Class),类型突变会导致隐藏类重建,降低执行效率(如
-
避免强制类型转换
- 显式转换类型:如
Number(str)替代+str,String(num)替代num+"",减少 V8 的隐式转换开销。
- 显式转换类型:如
-
函数优化
- 避免 arguments 对象:用剩余参数(
...args)替代,V8 对剩余参数的优化更好。 - 函数参数数量稳定:参数数量固定的函数更易被 V8 优化为内联函数(Inline)。
- 避免 arguments 对象:用剩余参数(
-
内存管理
- 减少闭包引用:闭包会保留外部变量引用,避免不必要的闭包导致内存无法回收。
- 及时释放大对象:不再使用的大数组 / 对象设为
null,帮助 V8 垃圾回收(GC)识别回收目标。
**3、watchEffect和watch区别
4、git merge 和git rebase区别
5、介绍 JS 有哪些内置对象?
数据封装类对象:Object、Array、Boolean、Number、String 其他对象:Function、Arguments、Math、Date、RegExp、Error ES6 新增对象:Symbol、Map、Set、Promises、Proxy、Reflect
6、JS 的基本数据类型和引用数据类型
基本(原始)数据类型: number、string、boolean、undefined, null, symbol 引用数据类型: Object、Function、Array
7、DOM 元素e的 e.getAttribute(propName)和 e.propName 有什么区别和联系
e.getAttribute:获取的是标签上属性 可以通过e.setAttribute(propName, propValue)设置标签上属性 e.propName:获取的是元素对象上属性
8、offsetWidth/offsetHeight,clientWidth/clientHeight,scrollWidth/scrollHeight 的区别?
offsetWidth/offsetHeight 返回值包含 content + padding + border + 包含滚动条,效果与 e.getBoundingClientRect()相同 clientWidth/clientHeight 返回值只包含 content + padding,如果有滚动条,也不包含滚动条 scrollWidth/scrollHeight 返回值包含 content + padding + 溢出内容的尺寸