前端面试题

92 阅读8分钟

1、频繁变动资源」:设置Cache-Control:no-cache,使浏览器每次都发送请求到服务器,配合Last-Modified/ETag验证资源是否有效 「不常变化资源」:设置Cache-Control:max-age=31536000,对文件名哈希处理,当代码修改后生成新的文件名,当HTML文件引入文件名发生改变才会下载最新文件 具体是哪些文件?

image.png

2、「加载优化」:资源在加载时可做的性能优化 「执行优化」:资源在执行时可做的性能优化 「渲染优化」:资源在渲染时可做的性能优化 「样式优化」:样式在编码时可做的性能优化 「脚本优化」:脚本在编码时可做的性能优化 「V8引擎优化」:针对V8引擎特征可做的性能优化 具体是哪些?

一、「加载优化」:资源加载时的性能优化

核心目标:减少资源加载时间、降低请求开销、优先加载关键资源。

  1. 资源压缩与合并

    • 压缩:JS 用 Terser,CSS 用 CSSNano,HTML 用 html-minifier;图片用 WebP/AVIF 格式(比 JPEG 小 30%+),非透明图优先 WebP,透明图用 PNG8 或 WebP。
    • 合并:小图标合并为 Sprite 图(减少请求),非关键 JS/CSS 按需合并(避免过大单文件)。
  2. 合理使用缓存

    • 静态资源(CSS/JS/ 图片):Cache-Control: max-age=31536000 + 文件名哈希(如app.xxx.js)。
    • 频繁变动资源(HTML/API 数据):no-cache + Last-Modified/ETag验证。
  3. 延迟与异步加载

    • 非关键 JS:用async(加载完立即执行,顺序无关)或defer(DOM 解析完执行,按顺序)。
    • 图片 / 视频:懒加载(loading="lazy"属性,或监听IntersectionObserver),优先加载可视区资源。
    • 组件懒加载:路由级拆分(如 React.lazy+Suspense,Vue 异步组件)。
  4. CDN 与资源分发

    • 静态资源部署到 CDN(利用边缘节点缓存,减少跨地域延迟)。
    • 大文件分片加载(如视频用 HLS/DASH 协议,分成小片段按需加载)。
  5. 减少请求开销

    • 启用 HTTP/2(多路复用,减少连接建立成本)或 HTTP/3(QUIC 协议,抗丢包)。
    • 减少 Cookie 体积(静态资源域名与主域名分离,避免不必要的 Cookie 携带)。
  6. **优化加载顺序

    • 预加载关键资源:使用 <link rel="preload"> 强制浏览器优先下载关键资源(如关键CSS、Web字体)。
    • 懒加载非关键资源:使用 loading="lazy" 延迟加载视口外的图片和 iframe。
    • 异步加载脚本:使用 async 或 defer 属性,避免 JS 阻塞 HTML 解析。

二、「执行优化」:资源执行时的性能优化

核心目标:减少 JS/CSS 执行时间,避免主线程阻塞。

  1. JS 执行优化

    • 避免长任务(执行时间 > 50ms):将复杂逻辑拆分为微任务(Promise)或宏任务(setTimeout),利用 Web Worker 处理计算密集型操作(如数据解析、图表渲染)。

    • 优化循环与递归:减少循环嵌套(如 O (n²)→O (n)),递归改为迭代(避免栈溢出),使用break/continue提前退出无效循环。

    • 减少 DOM 操作频率:批量修改 DOM(先脱离文档流,如documentFragment,修改后再插入)。

    • 使用 Web Workers 将纯计算密集型任务(如图像处理、数据解析)放到 Worker 中,避免阻塞 UI 线程。

    • 优化事件处理 : 防抖(Debounce)和节流(Throttle) :控制 resizescrollinput 等高频事件的触发频率。

    • 事件委托:利用事件冒泡,将事件监听器绑定在父元素上,减少内存占用和绑定数量。

  2. CSS 执行优化

    • 避免复杂选择器:减少嵌套层级(如div:nth-child(2) > .class ~ span改为扁平类名),浏览器匹配选择器是从右向左,复杂选择器计算耗时。
    • 减少@import@import会阻塞后续 CSS 解析,改用<link>并行加载。

三、「渲染优化」:资源渲染时的性能优化

核心目标:减少回流(重排)、重绘,提升渲染流畅度。

  1. 减少回流与重绘

    • 批量修改样式:用class一次性切换样式,而非逐个修改style属性。
    • 避免触发回流的属性:读取offsetWidthscrollTop等布局属性后立即修改样式(会导致浏览器强制同步布局),应先集中读取,再集中修改。
    • 使用will-changetransform:将频繁动画元素设为will-change: transform,动画用transform(仅触发合成层,无回流)而非top/left
  2. 优化渲染树

    • 移除无效 DOM:删除隐藏元素(display: none)或冗余节点(如空<div>),减少渲染树规模。
    • 合理使用visibility: hiddendisplay: none:前者保留布局(重绘不回流),后者不保留(回流),按需选择。
  3. 合成层优化

    • 避免过多合成层:每个合成层占用内存,过多会导致卡顿(如大量transform: translateZ(0)滥用)。
    • 大图片 / 视频用object-fit:避免缩放导致的合成层重计算。
  4. 使用 CSS3 硬件加速

-   对动画元素使用 `transform` 和 `opacity` 属性。这些属性由合成器处理,不涉及主线程和重排/重绘。
-   可以触发硬件加速的属性:`transform`, `opacity``filter``will-change`
  1. 优化动画

    • 优先使用 CSS 动画(animation)和过渡(transition),而非 JavaScript 控制的动画。

四、样式优化

核心目标:编写高效、可维护的 CSS

  1. 选择器性能

    • 避免使用过于复杂的选择器(如 .nav ul li a),保持简洁。
    • 避免使用通配符 * 和深层级选择器。
  2. 避免使用昂贵的属性

    • 某些属性(如 box-shadowborder-radiusfilter)在绘制时计算成本较高,应谨慎使用,尤其是在需要动画的元素上。
  3. 使用 Flexbox 或 Grid 布局

    • 现代布局方案(Flexbox、Grid)的性能通常优于传统的 Float 或 Table 布局。
  4. 内联关键 CSS

    • 将首屏渲染所需的关键样式通过 <style> 标签内联在 HTML 的 <head> 中,减少首次渲染的 RTT。

五、「脚本优化」:脚本编码时的性能优化

核心目标:提升 JS 执行效率,减少内存占用。

  1. 变量与函数优化

    • 减少全局变量:全局变量常驻内存,优先用局部变量(作用域链短,访问快)。
    • 函数防抖(Debounce)与节流(Throttle):高频事件(resize、scroll、input)用防抖(如搜索输入)或节流(如滚动加载)限制执行频率。
  2. 数据处理优化

    • Map/Set替代对象 / 数组:查找效率更高(Map.get为 O (1),数组indexOf为 O (n))。
    • 避免不必要的数据复制:大数组用slice(浅拷贝)而非JSON.parse(JSON.stringify())(深拷贝耗时),必要时用结构化克隆(structuredClone)。
  3. 事件处理优化

    • 事件委托:父元素代理子元素事件(如列表项点击,绑定到<ul>),减少事件监听器数量。
    • 及时解绑事件:组件卸载时移除addEventListener绑定,避免内存泄漏。
  4. DOM 操作优化

    • 批量修改 DOM:使用 DocumentFragment 或在离线 DOM 上操作,最后一次性插入文档。
    • 减少对 DOM 的查询:将查询结果缓存起来。
  5. 流程控制优化

    • 在循环中,for 循环通常比 forEach 等函数式方法更快。
    • 使用 switch 代替多个 if-else

六、「V8 引擎优化」:针对 V8 特征的优化

V8 是 Chrome/Node.js 的 JS 引擎,优化需贴合其编译(JIT)和内存管理机制。

  1. 类型稳定化

    • 避免同一变量频繁切换类型:V8 会为对象创建隐藏类(Hidden Class),类型突变会导致隐藏类重建,降低执行效率(如let a = 1; a = "str")。
    • 数组元素类型统一:纯数字数组([1,2,3])比混合类型数组([1, "a", {}])更高效,V8 会优化为连续内存存储。
  2. 避免强制类型转换

    • 显式转换类型:如Number(str)替代+strString(num)替代num+"",减少 V8 的隐式转换开销。
  3. 函数优化

    • 避免 arguments 对象:用剩余参数(...args)替代,V8 对剩余参数的优化更好。
    • 函数参数数量稳定:参数数量固定的函数更易被 V8 优化为内联函数(Inline)。
  4. 内存管理

    • 减少闭包引用:闭包会保留外部变量引用,避免不必要的闭包导致内存无法回收。
    • 及时释放大对象:不再使用的大数组 / 对象设为null,帮助 V8 垃圾回收(GC)识别回收目标。

**3、watchEffect和watch区别

image.png

4、git merge 和git rebase区别

image.png

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 + 溢出内容的尺寸