前端高频面试题合集:HTTPS、WebSocket、HTTP2、Promise组合方法、Webpack vs Vite

目录

前端高频面试题合集:HTTPS、WebSocket、HTTP2、Promise组合方法、Webpack vs Vite

一、HTTPS 相关面试题

基础必问

1. HTTP 和 HTTPS 的区别是什么?HTTPS 解决了 HTTP 哪些安全问题?

答:

  • 端口:HTTP默认80,HTTPS默认443;
  • 传输:HTTP明文传输,HTTPS基于TLS加密传输;
  • 安全缺陷:HTTP存在窃听、数据篡改、服务器身份伪造三大风险;
  • HTTPS解决:①防窃听:传输数据加密,第三方无法读取;②防篡改:消息摘要校验,数据改动会校验失败;③防冒充:数字证书校验服务端真实身份。
  • 性能:HTTPS多一次TLS握手,有轻微性能损耗。

2. HTTPS 端口是多少?

答:

  • HTTP端口80,HTTPS端口443。

3. HTTPS 是基于什么加密实现的?对称加密、非对称加密、数字证书分别作用?

答:HTTPS混合使用对称+非对称加密,配合数字证书完成安全通信:

  • 对称加密:加解密共用同一密钥,速度快,用来传输业务数据;
  • 非对称加密:公钥加密、私钥解密,运算慢,仅用于交换对称密钥;
  • 数字证书:CA机构颁发,存储域名、服务器公钥、CA签名,证明服务器合法身份,防止中间人伪造公钥。

4. 什么是中间人攻击?HTTPS 如何防止中间人劫持?

答:中间人劫持网络流量,伪造服务端公钥骗取客户端的对称密钥,全程窃听篡改数据。
防御:浏览器校验服务端数字证书,合法证书由可信CA签名,中间人无法伪造有效证书,校验失败直接拦截页面。

5. SSL/TLS 握手流程完整讲一遍(简化5步)

答:
第一步,客户端给出协议版本号、一个客户端生成的随机数(Client random),以及客户端支持的加密方法
第二步,服务端确认双方使用的加密方法,并给出数字证书、以及一个服务器生成的随机数
第三步,客户端确认数字证书有效,然后生成一个新的随机数(Premaster secret),并使用数字证书中的公钥,加密这个随机数,发给服务端
第四步,服务端使用自己的私钥,获取客户端发来的随机数(即Premaster secret)。
第五步,客户端和服务端根据约定的加密方法,使用前面的三个随机数,生成"对话密钥"(session key),用来加密接下来的整个对话过程
总结
客户端发起 HTTPS 请求,服务端返回证书,客户端对证书进行验证,验证通过后本地生成用于构造对称加密算法的随机数
通过证书中的公钥对随机数进行加密传输到服务端(随机对称密钥),服务端接收后通过私钥解密得到随机对称密钥,之后的数据交互通过对称加密算法进行加解密。(既有对称加密,也有非对称加密)

6. 数字证书包含什么信息?CA 机构作用是什么?自签证书会有什么问题?

答:

  • 证书内容:域名、公钥、证书有效期、颁发机构CA、签名算法、CA数字签名;
  • CA作用:可信第三方,负责审核域名所有权,签发合法证书;
  • 自签证书问题:不在浏览器内置可信根证书列表,浏览器判定不安全,弹出拦截警告,生产环境禁止使用。

7. 什么是证书链、根证书?浏览器为什么信任根证书?

答:

  • 根证书:顶级CA证书,预装在操作系统/浏览器本地,自带信任标记;
  • 证书链:服务器证书→中级CA证书→根证书,层层签名校验;
  • 信任逻辑:根证书内置本地,根证书公钥内置,可校验下级证书签名,形成完整信任链。

进阶深挖

1. 对称加密和非对称加密优缺点,为什么 HTTPS 不全程用非对称加密?

答:

  • 对称加密:优点速度极快;缺点密钥分发不安全;
  • 非对称加密:优点无需提前分发密钥,安全交换;缺点数学运算量大,速度极慢;
  • 不全程使用原因:网页传输大量图片、JS、文本,海量数据用非对称加密会严重卡顿,仅用它交换短小的对称密钥。

场景应用题

1. 本地开发怎么配置 HTTPS(自签证书 + vite/webpack https 配置)?

答:

  1. openssl命令生成crt证书文件与key私钥文件;
  2. Webpack devServer中配置https: { cert, key }
  3. Vite server配置server: { https: { cert, key } }
  4. 首次访问需手动导入证书到系统信任列表,否则浏览器拦截。

2. Nginx 配置 HTTPS 核心配置项是什么?

答:监听443端口;开启ssl;配置ssl_certificate证书、ssl_certificate_key私钥;配置ssl_protocols TLSv1.2 TLSv1.3;配置ssl_ciphers加密套件;配置HSTS头。

3. 接口 HTTPS 请求报错证书失效如何排查?

答:①核对证书有效期;②核对证书绑定域名;③检查服务器系统时间是否偏差;④确认CA是否可信;⑤检查Nginx证书文件路径是否正确。

二、WebSocket 面试题

基础题

1. WebSocket 和 HTTP 的区别?为什么 HTTP 不适合做实时通讯?

答:

  • HTTP:短连接、单向一问一答,每次请求新建TCP连接,头部冗余;
  • WebSocket:基于HTTP一次握手升级协议,复用同一条TCP长连接,双向收发消息;
  • HTTP实时方案缺陷:轮询频繁创建连接、长轮询延迟高、头部重复传输,资源开销大,WebSocket一次握手永久复用连接,开销极低。

2. WebSocket 握手过程是怎样的?请求头关键字段作用?

答:握手本质是一次GET HTTP请求,关键字段:

  • Connection: Upgrade:告知服务器需要升级协议;
  • Upgrade: websocket:指定升级目标协议为WebSocket;
  • Sec-WebSocket-Key:客户端随机Base64密钥,用于校验;
  • Sec-WebSocket-Accept:服务端将Key拼接固定字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11后SHA1加密返回,校验客户端合法性,防止跨站伪造。

3. WebSocket 协议端口?ws:// 80,wss:// 443;wss 是加密版 WebSocket。

答:明文ws协议复用HTTP 80端口;加密wss协议复用HTTPS 443端口,流量经过TLS加密,安全防窃听。

4. WebSocket 原生 API 有哪些事件:open /message/error /close 分别触发时机。

答:

  • open:握手完成,连接成功时触发;
  • message:服务端推送消息到达客户端触发;
  • error:连接、收发消息出现异常触发;
  • close:连接正常/异常关闭时触发,可获取关闭码。

5. readyState 四个状态值

答:
0 CONNECTING:正在握手建立连接;
1 OPEN:连接正常,可收发消息;
2 CLOSING:主动发起关闭流程;
3 CLOSED:连接彻底断开,不可通信。

原理 & 进阶

1. Sec-WebSocket-Key 加密规则:服务端如何生成 Accept 返回?为什么需要这个校验?

答:
生成规则:客户端key拼接固定GUID字符串,进行SHA1哈希,再Base64编码得到Accept值;
校验目的:防止普通HTTP请求意外升级WebSocket,抵御跨站伪造请求攻击。

2. WebSocket 帧结构简单介绍(文本帧、二进制帧、关闭帧、ping/pong)

答:WebSocket所有数据以帧传输,常见类型:

  • 文本帧:传输字符串消息;
  • 二进制帧:传输ArrayBuffer、Blob二进制数据;
  • 关闭帧:协商断开连接;
  • ping/pong心跳帧:检测连接存活。

3. ping/pong 心跳机制是什么?为什么要做心跳?怎么处理断线重连?

答:

  • 机制:客户端定时发送ping帧,服务端必须返回pong帧;
  • 作用:防火墙/路由会静默切断闲置长连接,心跳检测TCP真实连通状态;
  • 断线处理:超时未收到pong判定断开,执行重连逻辑。

4. WebSocket 断线怎么实现自动重连?封装思路(延迟重试、最大重试次数、指数退避)

答:

  1. 监听close/error事件触发重连;
  2. 指数退避延迟:1s、2s、4s、8s…上限30s,避免瞬间大量重连压垮服务;
  3. 设置最大重试次数,超出则停止;
  4. 重连期间缓存待发送消息,恢复连接后批量补发。

1. WebSocket 二进制数据怎么传输?ArrayBuffer、Blob 处理。

答:发送时直接传入ArrayBuffer/Blob,接收message事件中e.data会自动对应二进制类型,可处理文件、音视频流。

对比 & 场景

1. 实时通讯方案对比:WebSocket / SSE / 轮询 / 长轮询

答:

  • 短轮询:定时发HTTP,延迟高、性能差,适合低实时性场景;
  • 长轮询:服务端挂起请求,有消息立即返回,单向通信;
  • SSE:HTTP长连接,仅服务端单向推送,仅支持文本,无需握手;
  • WebSocket:TCP长连接双向收发,支持二进制,高实时聊天、直播、大屏。

2. SSE 和 WebSocket 区别:单向 / 双向、协议、兼容性、多消息推送。

答:

  • 通信方向:SSE服务端单向推送到客户端;WebSocket双向互发;
  • 底层:SSE基于普通HTTP,WebSocket需要协议升级握手;
  • 数据:SSE仅文本;WebSocket支持二进制;
  • 断开重连:SSE浏览器原生自动重连,WebSocket需手动封装。

3. WebSocket 跨域问题怎么解决?和 http 跨域一样吗?

答:握手阶段仍是标准HTTP请求,遵循CORS跨域规则,服务端配置Access-Control-Allow-Origin即可;WebSocket数据传输阶段无跨域限制。

4. 项目中如何封装 WebSocket(消息队列、重连、心跳、统一错误处理)?

答:封装类维护状态、心跳定时器、消息缓存队列;提供send方法,未连接时存入队列;监听所有事件统一捕获错误;内置指数退避重连;对外提供onMessage、onClose回调。

5. WebSocket 结合 HTTP2 有什么优势?

答:HTTP2单条TCP多路复用,WebSocket长连接与页面静态资源共享同一TCP,减少多次TLS握手开销;HPACK压缩降低握手请求头体积,提升性能。

6. 页面离线 / 切后台后 WebSocket 断开怎么优化?

答:页面可见性APIvisibilitychange,切后台暂停心跳;切前台主动检测连接状态,断开则自动重连;使用浏览器后台持久化API维持连接。

三、HTTP/2.0 面试题

基础问答

1. HTTP1.0、1.1、2.0 分别有什么缺陷,HTTP2 解决了哪些痛点?

答:

  • HTTP1.0:每次请求新建TCP,无连接复用;
  • HTTP1.1缺陷:串行请求队头阻塞、请求头重复冗余、同域名仅6条TCP并发;
  • HTTP2核心解决:二进制分帧、单TCP多路并发、头部压缩、服务端推送、请求优先级,彻底解决1.1性能瓶颈。

2. HTTP2 基于什么协议?TCP 还是 UDP?HTTPS 下才能默认启用(大部分浏览器限制)。

答:HTTP2底层基于TCP;主流浏览器仅在HTTPS加密环境下支持HTTP2,明文HTTP默认禁用。HTTP3基于UDP+QUIC。

3. HTTP2 五大核心特性分别解释作用

答:

  1. 二进制分帧:文本协议改为二进制帧,解析效率更高;
  2. 多路复用:单TCP连接并发处理数十个请求,无应用层阻塞;
  3. HPACK头部压缩:静态+动态字典缓存重复Header,大幅减少传输体积;
  4. 服务器推送Server Push:页面加载时主动推送后续依赖资源;
  5. 请求优先级:标记资源权重,浏览器优先加载CSS、关键JS。

4. 什么是多路复用?和 HTTP1.1 管道化(pipeline)有什么本质区别?

答:

  • Pipeline:请求串行发送,响应必须严格按请求顺序返回,慢请求阻塞全部后续响应,仍存在队头阻塞;
  • 多路复用:所有请求独立流,响应乱序返回,互不阻塞,真正并行传输。

5. 头部压缩 HPACK 原理,为什么能减少 header 体积?

答:维护静态字典(通用Header如User-Agent、Cookie)与动态字典(本次会话出现过的自定义Header),重复字段仅传输索引数字,替代完整字符串,大幅压缩头部体积。

进阶深挖

1. 二进制分帧层是什么?流、消息、帧三者层级关系?

答:二进制分帧是HTTP2底层抽象层;层级从小到大:帧(最小传输单元)→消息(一次完整请求/响应,由多个帧组成)→流(TCP内独立双向通信通道,承载多条消息)。

2. 流的优先级有什么用?浏览器怎么控制资源加载顺序?

答:每个流附带权重标识,浏览器给关键CSS、首屏JS分配高权重,服务器优先传输高优先级流资源,优化首屏加载速度。

3. Server Push 服务器推送是什么?优缺点,什么场景不建议用?

答:服务端预判页面依赖,主动推送资源给客户端缓存;
优点:省去浏览器发起二次请求的RTT延迟;
缺点:容易推送用户不需要的资源,浪费带宽;缓存命中时重复推送造成冗余;
不建议场景:动态路由按需加载资源、用户已缓存静态资源。

4. HTTP2 多路复用会不会有队头阻塞?和 HTTP1.1 的队头阻塞区别?

答:HTTP2仅存在TCP传输层队头阻塞(单数据包丢包阻塞整条TCP);HTTP1.1是应用层队头阻塞,一个慢请求卡住所有响应;HTTP2丢包仅阻塞对应单一流,其余请求正常传输,影响极小。

5. HTTP2 同一域名下最多多少并发流?默认 100 个。

答:服务端默认配置单TCP最大并发100条流,足够页面所有静态资源并行加载。

6. HTTP3 和 HTTP2 核心区别(QUIC+UDP),简单拓展。

答:HTTP2基于TCP,丢包会阻塞整条连接;HTTP3基于UDP的QUIC协议,每条流独立传输,单流丢包不影响其他;支持0-RTT握手,弱网、移动网络体验更好。

场景 & 工程题

1. 前端项目部署开启 HTTP2 需要 Nginx 做什么配置?

答:Nginx配置listen 443 ssl http2;,ssl证书配置完整,重启服务即可启用HTTP2。

2. HTTP2 环境下,雪碧图、合并 JS 还有必要吗?为什么?

答:没必要。多路复用下多个小文件并行加载无阻塞,拆分文件更利于浏览器长效缓存;打包合并的性能收益大幅降低。

3. 为什么 HTTP2 建议域名拆分减少?

答:HTTP1.1同域名TCP并发限制6个,需要多域名突破限制;HTTP2单域名单TCP支持百路并发,拆分多域名会创建多条TCP,增加TLS握手开销,性能变差。

4. 抓包如何区分当前是 HTTP1.1 还是 HTTP2?

答:抓包工具查看协议字段,HTTP2标识为h2;HTTP1.1显示HTTP/1.1。

四、Promise.all/race /allSettled 区别 + 底层实现

概念对比基础题

1. 三个方法分别接收什么参数?

答:接收一个可迭代数组,数组元素可以是Promise实例、普通同步值,内部统一用Promise.resolve()包裹。

2. Promise.all 规则

答:全部Promise成功才resolve,返回结果数组(顺序与入参一致);任意一个Promise失败,立即整体reject,丢弃其余结果。

3. Promise.race 规则

答:竞速执行,第一个完成(无论成功/失败)的Promise结果作为最终返回值;其余Promise会继续执行,但结果被丢弃。

4. Promise.allSettled 规则

答:等待全部Promise执行完毕,永远不会reject;返回数组,每项包含status: fulfilled/rejected,搭配value/reason。

5. 补充拓展:Promise.any

答:任意一个Promise成功就resolve;所有Promise全部失败才reject,返回全部失败原因聚合错误。

6. 分别说下四个 API 的适用业务场景

答:

  • all:多个接口必须全部成功才能渲染页面;
  • race:接口超时、多请求竞速取最快结果;
  • allSettled:批量导入/上传,需要统计全部成功失败条数;
  • any:多备用镜像接口,任一返回数据即可。

场景应用题

1. 批量请求接口,希望全部成功再渲染,失败一个整体报错用哪个?

答:Promise.all

2. 批量请求,不管成功失败都要收集每个接口结果做统计,用哪个?

答:Promise.allSettled

3. 多个请求取最快返回的结果(超时兜底),用哪个?

答:Promise.race

4. 多个备用接口,有一个成功就返回,全部挂了才报错?

答:Promise.any

5. Promise.all 中某个请求失败,如何不让整体崩溃?

答:方案1:给每个Promise单独添加.catch()捕获错误,将失败转为fulfilled状态;方案2:直接使用allSettled。

6. 如何给批量请求统一设置超时?

答:单个接口Promise与延时reject的定时器Promise放入race,超时定时器先完成则抛出超时错误。

原理手写题

1. 手写实现 Promise.all

function myAll(promises) {
  return new Promise((resolve, reject) => {
    const resList = [];
    let finishCount = 0;
    const len = promises.length;
    if (len === 0) return resolve([]);
    promises.forEach((item, idx) => {
      Promise.resolve(item)
        .then((val) => {
          resList[idx] = val;
          finishCount++;
          if (finishCount === len) resolve(resList);
        })
        .catch((err) => reject(err));
    });
  });
}

2. 手写 Promise.race

function myRace(promises) {
  return new Promise((resolve, reject) => {
    promises.forEach((item) => {
      Promise.resolve(item).then(resolve, reject);
    });
  });
}

3. 手写 Promise.allSettled

function myAllSettled(promises) {
  return new Promise((resolve) => {
    const resList = [];
    let finishCount = 0;
    const len = promises.length;
    if (len === 0) return resolve([]);
    promises.forEach((item, idx) => {
      Promise.resolve(item)
        .then((value) => (resList[idx] = { status: "fulfilled", value }))
        .catch((reason) => (resList[idx] = { status: "rejected", reason }))
        .finally(() => {
          finishCount++;
          if (finishCount === len) resolve(resList);
        });
    });
  });
}

4. 手写 Promise.any

function myAny(promises) {
  return new Promise((resolve, reject) => {
    const errList = [];
    let failCount = 0;
    const len = promises.length;
    if (len === 0) reject(new AggregateError([], "All promises failed"));
    promises.forEach((item) => {
      Promise.resolve(item)
        .then((val) => resolve(val))
        .catch((err) => {
          errList.push(err);
          failCount++;
          if (failCount === len) reject(new AggregateError(errList));
        });
    });
  });
}

5. Promise.all 遍历数组是同步遍历还是异步?执行顺序和数组顺序是否一致?

答:forEach同步遍历所有Promise并同时启动;结果数组顺序严格和入参数组一一对应,不受异步执行快慢影响。

6. 如果传入数组里有普通值(非 Promise)内部怎么处理?

答:统一用Promise.resolve(普通值)包装为成功态Promise。

深挖底层

1. Promise.all 是并发执行还是串行?

答:并发,所有Promise实例同时启动执行,不存在等待上一个完成再执行下一个。

2. race 中先完成的 promise 会中断其他 promise 执行吗?

答:不会,Promise一旦创建就会完整执行异步逻辑,race仅不再接收剩余Promise的结果。

3. 大量并发请求用 Promise.all 会有并发溢出,如何做并发限制?手写并发池

class RequestPool {
  constructor(maxNum) {
    this.max = maxNum;
    this.running = 0;
    this.taskQueue = [];
  }
  addTask(promiseFn) {
    return new Promise((resolve) => {
      this.taskQueue.push({ promiseFn, resolve });
      this.run();
    });
  }
  run() {
    if (this.running >= this.max || this.taskQueue.length === 0) return;
    this.running++;
    const { promiseFn, resolve } = this.taskQueue.shift();
    promiseFn().then((res) => {
      resolve(res);
      this.running--;
      this.run();
    });
  }
}
// 使用
const pool = new RequestPool(5); // 最多5个并发
const tasks = urlList.map((url) => pool.addTask(() => fetch(url)));
Promise.all(tasks);

五、Webpack vs Vite 区别

基础对比题

1. Webpack 和 Vite 最核心的区别是什么?

答:

  • 构建机制:Webpack全量打包;Vite开发环境基于浏览器原生ESM按需编译;
  • 底层工具:Webpack JS实现+Babel转译;Vite开发用Go写的esbuild预构建,生产用Rollup打包。

2. Vite 开发环境和生产环境分别用什么工具?Webpack 开发生产都是自身。

答:Vite开发:esbuild做第三方依赖预构建;Vite生产:Rollup完成打包、Tree-Shaking、压缩;Webpack开发、生产构建全部由Webpack自身完成。

3. 开发环境启动速度差异巨大的根本原因?

答:

  • Webpack:启动时递归解析全部项目依赖,打包生成完整bundle后才启动dev服务,项目越大启动越慢;
  • Vite:启动仅预构建第三方依赖缓存到本地,业务代码浏览器发起import请求时才实时单文件编译,冷启动极快。

4. 什么是 esbuild?为什么比 babel 快?

答:esbuild是Go语言编写的构建工具;Babel是JS单线程运行;esbuild充分利用多核CPU并行编译,极简AST处理逻辑,无冗余插件开销,速度提升数十倍。

5. Vite 的依赖预构建是什么?解决了什么问题?

答:启动时将node_modules第三方包批量处理:①CommonJS包转浏览器可识别ESM;②合并零散分包依赖,避免浏览器发起数千次import请求;产物缓存到.vite目录,二次启动复用缓存。

原理深挖题

1. Webpack 核心五大概念:Entry、Output、Loader、Plugin、Mode,分别作用。

答:

  • Entry:打包入口文件,定义构建起点;
  • Output:配置打包产物输出路径、文件名;
  • Loader:转换非JS资源(css、vue、图片);
  • Plugin:监听构建生命周期钩子,完成压缩、html生成、清理目录等复杂操作;
  • Mode:development/production,内置不同优化策略(开发不压缩、生产开启Tree-Shaking、代码压缩)。

2. Vite 开发时浏览器请求业务文件的完整流程

答:浏览器发起import请求 → Vite开发服务器拦截HTTP请求 → 实时编译单文件(ts转js、vue解析、css处理)→ 返回标准ESM代码给浏览器执行。

3. Webpack 热更新 HMR 原理 vs Vite HMR 原理,哪个更快?差异在哪?

答:Vite HMR更快;

  • Webpack HMR:重新编译受影响模块,更新整个bundle,依赖打包缓存,项目大更新卡顿;
  • Vite HMR:通过WebSocket监听文件改动,仅重新编译变更单文件,浏览器动态import替换模块,局部刷新毫秒级。

4. Webpack chunk 分割(code split)几种方式,Vite 怎么做分包?

答:
Webpack分包:①入口多entry分割;②import()动态导入;③splitChunks抽取公共代码、第三方包;
Vite生产基于Rollup分包,通过build.rollupOptions.output配置chunk拆分规则,自动分离vendor第三方包。

5. Vite 为什么生产环境不用 esbuild,改用 Rollup?

答:esbuild编译速度快,但Tree-Shaking、精细化代码压缩、产物兼容性、分包控制不如Rollup成熟;生产环境优先追求最小产物体积,因此使用Rollup。

6. Tree-Shaking 生效条件,Webpack 和 Vite 对 Tree-Shaking 支持差异。

答:生效条件:使用ESM import/export、mode=production、package.json sideEffects标记无副作用文件;
Webpack Tree-Shaking能力弱,依赖Terser压缩阶段删除死代码;Vite(Rollup)原生强Tree-Shaking,打包阶段直接剔除未引用代码。

7. Loader 和 Plugin 区别

答:Loader是文件转换器,作用于单个资源解析阶段;Plugin是生命周期钩子插件,贯穿构建全流程,处理打包整体逻辑。

8. Vite 插件系统和 Webpack Plugin 生命周期对比。

答:Webpack插件基于编译、生成、输出等多阶段钩子;Vite插件分为开发阶段钩子、Rollup标准打包钩子,API更简洁,执行分层更清晰。

优缺点 & 选型场景

1. Webpack 优势、劣势;Vite 优势、劣势分别是什么?

答:
Webpack:
优点:生态完善、兼容所有老旧CommonJS库、自定义构建能力极强;
缺点:启动、热更新随项目增大严重变慢,配置繁琐;
Vite:
优点:冷启动极速、毫秒级HMR、极简配置、esbuild预构建性能强;
缺点:老旧CommonJS包兼容坑多,超大型项目首次预构建慢,自定义插件生态不如Webpack。

2. 大型老项目为什么难从 Webpack 迁移到 Vite?常见兼容坑

答:大量旧式Webpack Loader/专属插件无Vite替代;项目依赖大量不规范CommonJS包;动态require、特殊资源处理逻辑不兼容;分包、环境变量、别名规则存在差异。

3. 什么场景适合用 Webpack,什么场景适合 Vite?

答:Webpack适合遗留大型老项目、高度自定义构建流程、多框架混合老旧项目;Vite适合Vue/React新项目、中小型后台管理系统、组件库开发。

4. Vite 开发环境有没有缺点?

答:依赖数量上千时首次预构建耗时久;部分老旧CommonJS第三方包转换异常;缓存失效会触发全量重新预构建。

5. Webpack 构建速度慢的优化手段

答:thread-loader多线程转译;开启cache持久化缓存;esbuild-loader替换babel;externals外部化大依赖;splitChunks分包;loader exclude排除node_modules。

6. Vite 构建性能优化手段

答:optimizeDeps强制预构建、缓存持久化;分包拆分第三方依赖;关闭不必要的转译插件;build.minify压缩优化。

实操 / 手写配置题

1. Webpack 手写基础配置

const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  entry: "./src/main.js",
  output: { path: __dirname + "/dist", filename: "bundle.js" },
  module: {
    rules: [
      { test: /\.css$/, use: ["style-loader", "css-loader"] },
      { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" },
    ],
  },
  plugins: [new HtmlWebpackPlugin({ template: "./index.html" })],
  devServer: { hot: true, open: true },
};

2. Vite 基础配置讲解

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
export default defineConfig({
  plugins: [vue()],
  resolve: { alias: { "@": path.resolve(__dirname, "./src") } }, // 路径别名
  server: {
    proxy: { "/api": { target: "http://localhost:3000", changeOrigin: true } },
  }, // 跨域代理
  build: { rollupOptions: { output: { manualChunks: { vendor: ["vue"] } } } }, // 分包
});

3. Webpack 如何处理图片、字体资源?Vite 中资源处理有什么不同?

答:Webpack使用file-loader、url-loader处理静态资源;Vite内置资源处理,小于阈值自动内联base64,大文件直接输出,无需额外loader。

4. Webpack externals 是什么?Vite 对应怎么配置外部化依赖。

答:externals将第三方依赖排除打包,运行时CDN引入;Vite配置build.rollupOptions.external实现外部化。

5. Vite 预构建缓存目录在哪?如何清除缓存?

答:缓存目录node_modules/.vite;删除文件夹或执行vite --force强制重新预构建。

6. 实现一个简单 Webpack Plugin / Vite 插件,打印构建时间

Vite插件示例:

function buildTime() {
  return {
    name: "build-time-plugin",
    buildStart() {
      this.start = Date.now();
    },
    buildEnd() {
      console.log("构建耗时", Date.now() - this.start + "ms");
    },
  };
}

拓展延伸题

1. Turbopack 是什么?Webpack 下一代工具,和 Vite 对比。

答:Webpack团队推出的Rust编写构建工具,兼顾Webpack完整生态与Vite的高速启动,目前生态成熟度低于Vite。

2. Rspack 和 Vite/Webpack 的差异。

答:Rspack基于Rust重写Webpack架构,API兼容Webpack配置,速度接近Vite,适合存量Webpack项目低成本提速。

3. 为什么 Create-React-App、Vue CLI 早期用 Webpack,Vue3/VuePress 主推 Vite?

答:Vue3发布时Vite成熟,原生ESM架构大幅提升开发体验;Vue CLI基于Webpack启动缓慢,新项目官方推荐Vite简化构建配置。

综合交叉面试题(压轴)

1. HTTPS + HTTP2 + WebSocket 同时开启下,页面请求链路是怎样的?性能提升点有哪些?

答:全部流量复用443加密端口,一次TLS握手生成单条TCP;HTTP2多路复用同时传输页面静态资源与WebSocket双向消息;HPACK压缩请求头;wss加密实时消息;减少多次TCP握手,并行加载资源,兼顾安全与性能。

2. 大量实时接口批量请求,用 Promise.allSettled + WebSocket 结合怎么设计?

答:批量HTTP接口用allSettled收集全部返回结果,批量数据通过WebSocket批量推送至前端;前端接收后用Promise异步分批处理消息,避免阻塞主线程。

3. Vite 开发环境基于 ESM,那 WebSocket 握手、HTTPS 证书在 Vite 里怎么配置?

答:vite.config.ts中server.https配置证书开启HTTPS;server.proxy配置ws:true代理WebSocket握手请求,wss复用443端口兼容HTTP2。

4. 后端接口超时:用 Promise.race 封装请求超时,底层依赖 HTTP/2 多路复用有什么优化?

答:HTTP2单TCP并发多个接口请求,无需新建TCP连接;Promise.race统一控制每个接口超时,避免串行请求长时间阻塞页面。

5. Webpack 打包后的资源部署 HTTPS + HTTP2 能做哪些性能优化?

答:开启HTTP2多路复用减少TCP连接;HPACK压缩请求头;HTTPS会话复用减少握手;合理拆分bundle利用浏览器长效缓存;关闭雪碧图、JS合并等HTTP1时代优化手段。

6. WebSocket 大批量消息并发接收,如何用 Promise 控制异步处理并发不阻塞页面?

答:实现Promise并发池,限制同时处理消息的异步任务数量;消息入队分批处理,使用requestIdleCallback在浏览器空闲时段执行,防止主线程卡顿。

posted @ 2026-06-23 10:03  雅痞_yuppie  阅读(17)  评论(0)    收藏  举报