前端高频面试题合集:HTTPS、WebSocket、HTTP2、Promise组合方法、Webpack vs Vite
- 前端高频面试题合集:HTTPS、WebSocket、HTTP2、Promise组合方法、Webpack vs Vite
- 一、HTTPS 相关面试题
- 二、WebSocket 面试题
- 三、HTTP/2.0 面试题
- 四、Promise.all/race /allSettled 区别 + 底层实现
- 五、Webpack vs Vite 区别
- 基础对比题
- 原理深挖题
- 1. Webpack 核心五大概念:Entry、Output、Loader、Plugin、Mode,分别作用。
- 2. Vite 开发时浏览器请求业务文件的完整流程
- 3. Webpack 热更新 HMR 原理 vs Vite HMR 原理,哪个更快?差异在哪?
- 4. Webpack chunk 分割(code split)几种方式,Vite 怎么做分包?
- 5. Vite 为什么生产环境不用 esbuild,改用 Rollup?
- 6. Tree-Shaking 生效条件,Webpack 和 Vite 对 Tree-Shaking 支持差异。
- 7. Loader 和 Plugin 区别
- 8. Vite 插件系统和 Webpack Plugin 生命周期对比。
- 优缺点 & 选型场景
- 实操 / 手写配置题
- 拓展延伸题
- 综合交叉面试题(压轴)
- 1. HTTPS + HTTP2 + WebSocket 同时开启下,页面请求链路是怎样的?性能提升点有哪些?
- 2. 大量实时接口批量请求,用 Promise.allSettled + WebSocket 结合怎么设计?
- 3. Vite 开发环境基于 ESM,那 WebSocket 握手、HTTPS 证书在 Vite 里怎么配置?
- 4. 后端接口超时:用 Promise.race 封装请求超时,底层依赖 HTTP/2 多路复用有什么优化?
- 5. Webpack 打包后的资源部署 HTTPS + HTTP2 能做哪些性能优化?
- 6. WebSocket 大批量消息并发接收,如何用 Promise 控制异步处理并发不阻塞页面?
前端高频面试题合集: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 配置)?
答:
- openssl命令生成crt证书文件与key私钥文件;
- Webpack devServer中配置
https: { cert, key }; - Vite server配置
server: { https: { cert, key } }; - 首次访问需手动导入证书到系统信任列表,否则浏览器拦截。
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 断线怎么实现自动重连?封装思路(延迟重试、最大重试次数、指数退避)
答:
- 监听close/error事件触发重连;
- 指数退避延迟:1s、2s、4s、8s…上限30s,避免瞬间大量重连压垮服务;
- 设置最大重试次数,超出则停止;
- 重连期间缓存待发送消息,恢复连接后批量补发。
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 五大核心特性分别解释作用
答:
- 二进制分帧:文本协议改为二进制帧,解析效率更高;
- 多路复用:单TCP连接并发处理数十个请求,无应用层阻塞;
- HPACK头部压缩:静态+动态字典缓存重复Header,大幅减少传输体积;
- 服务器推送Server Push:页面加载时主动推送后续依赖资源;
- 请求优先级:标记资源权重,浏览器优先加载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在浏览器空闲时段执行,防止主线程卡顿。

浙公网安备 33010602011771号