面试
面试知识点汇总(TreeShaking/性能优化等)
[!info] related notes
面试
入口
- frontend-interview-high-frequency-moc - 当前前端高频面试题主入口
- frontend-engineering-moc - 前端工程化与 AI 工程化知识入口
Rollup
Rollup 是一款专注于 JavaScript 模块打包 的工具,由 Rich Harris(Svelte 作者)开发。它的设计理念与 Webpack 有显著不同,更强调 轻量、高效和面向未来的模块化代码。
核心设计理念:
- 面向 ESM
- Tree Shaking 优先
- 简单高效
- 适合库/框架开发
核心特性:
- Tree Shaking
- 输出格式灵活
- 插件系统
- 代码分割
ref 和 reactive
| 特性 | ref | reactive |
|---|---|---|
| 数据类型 | 所有类型 | 仅对象类型 |
| 访问方式 | 需 .value(模板自动解包) | 直接访问属性 |
| 实现原理 | RefImpl + 内部调用 reactive | Proxy 代理 |
| 对象替换 | 支持 | 不支持 |
| 深层监听 | 需显式启用 deep: true | 默认支持 |
| 适用场景 | 基本类型、灵活替换对象 | 复杂对象、嵌套结构 |
Vite 和 Webpack
Vite:
- 开发环境无需打包,速度快
- 生产环境使用 Rollup 打包,支持 Tree Shaking、代码分割等优化
- 热更新效率高
Webpack:
- 全程打包
- 成熟的生态系统,支持复杂的代码分割、插件扩展和旧浏览器兼容。
docker 与 虚拟机 的区别
docker
基于容器技术,共享宿主机的操作系统内核
通过命名空间(Namespace)和控制组(Cgroup)实现资源隔离
容器本质上是宿主机的进程
资源利用率高(硬件利用率可达60%-80%)
启动速度秒级
镜像体积小(通常为MB级)
进程级隔离,安全性较弱
典型应用场景:
- 开发环境一致
- 微服务架构
- 跨平台应用分发
- 临时测试环境
虚拟机
Hypervisor 虚拟化硬件
运行完整操作系统
资源消耗大
启动分钟级
镜像体积大
操作系统级隔离
SSR 应用
优点:
- SEO 友好
搜索引擎爬虫可以直接抓取服务端生成的完整HTML内容,无需依赖客户端JavaScript执行,显著提升搜索引擎收录效果 - 首屏加载速度快
服务器直接返回渲染后的 HTML - 低端设备兼容性
- 内容一致性
问题:
- 服务器性能压力
- 开发复杂度
- 安全风险
- 流失渲染与性能优化
- 部署与运维成本
js 有哪些 worker(Web Worker)
Web Worker是HTML5标准的一部分,允许在主线程外创建独立的后台线程(Worker线程)。这些线程与主线程并行运行,不共享内存和DOM,但可通过消息传递机制(postMessage和onmessage)进行通信。
JavaScript提供了多种 Worker 机制来实现多线程编程
- Web Workers / Dedicated Workers(专用Worker):
最基本的Worker类型,由主线程创建并专属于创建它的脚本
无法访问DOM,通过postMessage与主线程通信
适用于CPU密集型计算任务 - Shared Workers(共享Worker):
可以被多个浏览上下文(不同窗口、iframe等)共享
适用于需要跨窗口/标签页共享数据和状态的场景 - Service Workers:
主要用作网络代理,可拦截和处理网络请求 - Worklets:
轻量级专用Worker,用于扩展渲染管道 - Node.js中的Worker Threads:
允许在Node.js中使用真正的多线程
worker 通信:
- 通信机制
结构化克隆
共享内存 - 使用限制
无法操作 DOM
同源策略
生命周期管理
Electron 底层有几个线程
- 主进程
- 渲染进程
- GPU 进程
- 插件进程
- 实用程序进程
Cookie
设置存储时间:
- expires
绝对时间 - max-age
相对时间
存储位置:
未设置过期时间:会话 Cookie(内存中,关闭浏览器失效)。
设置过期时间:持久化 Cookie(硬盘中)。
localStorage
使用 localStorage.clear() 方法可以一次性清空当前域名下的所有 localStorage 数据
通过 localStorage.removeItem(key) 删除特定键值对
使用函数模拟定期清除
场景:
- 用户数据持久化、偏好设置
- 本地缓存、性能优化
- 离线应用程序支持
- 跨页面数据传递
- 用户登录状态与身份验证
- 表单数据自动填充
- 跨标签页通信(监听 storage 事件)
PWA
渐进式增强(Progressive Enhancement)
关键技术组件:
- Service Worker
这是PWA的核心技术之一,负责离线缓存、推送通知、后台同步等功能。Service Worker是一段独立的JavaScript脚本,可以在后台处理网络请求,缓存数据和推送通知 - Web App Manifest
一个JSON文件,用于描述PWA应用的名称、图标、启动URL等信息,让浏览器可以将Web应用添加到主屏幕 - HTTPS
PWA必须通过HTTPS协议提供服务,确保用户数据的安全 - Push API
用于向用户发送推送通知 - Cache API
用于缓存静态资源
工作原理:
- 拦截网络请求
Service Worker可以拦截应用发出的所有HTTP请求 - 缓存策略
开发者可以自定义缓存策略,决定哪些资源应该被缓存以及如何响应缓存和网络请求 - 离线支持
- 后台同步
响应式设计的实现方式
响应式设计(Responsive Web Design, RWD)的核心是通过动态调整布局、内容和功能,使网页适配不同设备的屏幕尺寸和分辨率。
关键技术:
- 流式布局
使用百分比、vw/vh等相对单位替代固定像素,使元素尺寸随容器或视口变化。 - 媒体查询
通过CSS检测设备特性(如屏幕宽度、方向),应用不同的样式规则。 - 弹性媒体
图片和视频使用max-width: 100%或srcset属性,按需加载适配尺寸的资源。
前端工程化
- 性能优化
- RestFul API
- 虚拟DOM、真实DOM
Tree Sharking
Tree Shaking(摇树优化)是一种用于优化 JavaScript 应用的静态代码分析技术,其核心目标是通过移除未使用的代码(即“死代码”)来减小最终打包文件的体积,从而提升应用加载速度和运行性能。这一概念最早由 Rollup 提出,现已成为现代前端构建工具(如 Webpack、Rollup、Vite 等)的标配功能。
核心原理:
- 基于 ES6 模块的静态分析
Tree Shaking 依赖于 ES6 模块(ESM)的静态结构特性(import/export),因为 ESM 的依赖关系在编译时即可确定,而非像 CommonJS 模块那样动态解析。这使得构建工具能够通过抽象语法树(AST)分析代码的导出与引用关系,精确识别未使用的模块或变量。
若模块导出了 A 和 B,但仅 A 被其他模块引用,则 B 会被移除。 - 死代码消除(DCE)的进阶形式
传统 DCE 仅移除不可能执行的代码(如未调用的函数),而 Tree Shaking 更关注未引用的模块或导出值。 - 与副作用(Side Effects)的关联
若模块包含副作用(如修改全局变量、立即执行函数等),Tree Shaking 会保留这些代码以避免破坏程序逻辑。开发者可通过 package.json 的 “sideEffects” 字段显式标记这类模块(如 CSS 文件)。
Vue
- Vue2、Vue3区别
React
- 你知道react的fiber架构吗?hook-useFiber
- React用函数式组件怎么模拟出生命周期
- useLayoutEffect和useEffect有什么区别
作者:想去夏威夷的土拨鼠在攒经验 链接:https://www.nowcoder.com/feed/main/detail/39249e4d6def4f15bd1c7400f927f37b?sourceSSR=enterprise 来源:牛客网
浏览器
- 浏览器缓存机制
- 浏览器两个Tab页之间要怎么跨页面通信
- 浏览器垃圾回收机制
场景
- 在做大文件分片上传的时候,每一个文件的唯一标识要怎么去获得呢?
算法
- 链表反转
- 最长公共子序列
- dfs找最大岛屿
- 找最长不重复子串
计算机网络
https://github.com/wolverinn/Waking-Up/blob/master/Computer%20Network.md
TCP的三次握手
- 流程
- 半连接和全连接
- 为什么要三次握手
- 三次握手可以携带数据吗
TCP 的四次挥手
- 流程
- 为什么要四次挥手
- 能不能合并第二次和第三次
- 为什么第四次挥手客户端需要等待 2*MSL(报文段最长寿命)时间后才进入 CLOSED 状态
TCP 传输可靠性保障
- 如何保障
- 流量控制
- 拥塞控制
- ARQ 协议
- 超时重传
HTTP/0.9
最初想法是将文档存在服务器中,我们只需要从服务器获取存档
所以只有 GET,也没有请求头,并且请求完连接就断了
HTTP 1.0 和 HTTP 2.0 有什么区别
HTTP/1.0
- 增加了 HEAD、POST 等新方法
- 增加了响应状态码
- 引入了头部(请求头、响应头)
- 在请求中加入了 HTTP 版本号
- 引入了 Content-Type, 使传输数据不再局限于文本
HTTP/1.1
- 新增连接管理(keepalive),允许持久连接。
- 支持 pipeline ,无需等待前面的请求响应,即可发送第二次请求。
- 允许响应数据分块,即响应的时候不标明 Content-Length,客户端就无法断开连接,直到收到服务端的 EOF ,利于大文件传输
- 新增缓存的控制和管理
- 加入 Host 头,用在一台机子部署多个主机,多个域名解析又是同一个 IP,此时加入 Host 头就可以判断要访问哪个主机
HTTP/2
- 变为二进制协议,不再是纯文本
- 支持一个 TCP 连接发起多请求,移除了 pipeline
- 利用 HPACK 压缩头部,减少数据传输量
- 允许服务端主动推送数据
HTTP 2.0 和 3.0 有什么区别?
- 基于UDP协议
- 支持1-RTT 或 0-RTT 连接
- 多路复用+轮询
- 更高效的 QPACK 头部压缩算法
- 连接迁移
- 错误恢复
- 整个数据包加密
常见的 HTTP 状态码有哪些?
HTTP 请求包含哪些内容,请求头和请求体有哪些类型?
HTTP 中 GET 和 POST 的区别是什么?
- 语义
- 幂等
- 请求参数位置
- 安全性
- 缓存
WebSocket 与 HTTP 有什么区别?
- WebSocket 也是一个应用层的协议,基于 TCP。
- 支持实时双向通信
- 协议前缀
- 通信数据格式较轻量
- 支持扩展
服务端是如何解析 HTTP 请求的数据?(考察 HTTP 请求格式的了解程度)
- 接收请求
- 解析请求行
- 解析请求头
- 处理请求题
- 提取查询参数和路径参数
- 处理Cookie和会话
- 路由和业务逻辑处理
- 生成响应
- 发送响应并关闭连接
TCP 的粘包和拆包能说说吗? TCP 是面向字节流的协议,他只保证数据可靠传输,不维护消息边界。
粘包
定义:
多个数据包被合并成一个 TCP 段发送,接收方一次性读取到多个包的数据。
原因:
发送方:Nagle 算法(默认启用)会合并多个小数据包以提高网络效率。
接收方:缓冲区数据堆积,导致多个包被一次性读取。
拆包
定义:
一个数据包被拆分成多个 TCP 段发送,接收方需要多次读取才能拼凑完整数据。
原因:
发送方:数据包超过 MSS(Maximum Segment Size,通常 1460 字节)。
接收方:缓冲区大小不足,导致部分数据被截断。
解决方法:
- 固定消息长度,不足补充
\0 - 使用特殊分隔符标记结束
- 消息头写消息长度,消息体存储数据
TCP 初始序列号 ISN 怎么取值的?
ISN 的基本要求:
- 唯一性:防止旧连接的延迟报文被误认为新连接的数据
- 不可预测性:防止攻击者猜测序列号并发起会话劫持
- 均匀分布:充分利用 32 位序列号空间(约 40 亿个可能)
现代安全算法:结合时间、连接信息和密码学哈希
除了四次挥手,还有什么方法断开连接?
- RST
TCP 超时重传机制是为了解决什么问题? 网络通信中的数据包丢失问题
TCP 中何时会出现 RST(reset)报文?
连接建立阶段:
目标端口为监听
队列满
连接终止阶段:
强制终止连接
应用层主动终止(进程崩溃)
TIME-WAIT 状态终止
中间设备、安全策略
RST 的设计初衷是处理异常
TCP 的 SACK 的引入是为了解决什么问题? 选择性确认,接收方通过 SACK 选项告知发送方已收到的非连续数据块,避免重复传输
ARP 和 RARP 分别是什么?有什么区别?
ARP(Address Resolution Protocol,地址解析协议)和 RARP(Reverse Address Resolution Protocol,逆地址解析协议)
JWT Token 能说说吗?
JWT
常见的登录鉴权方式有哪些?各自的优缺点是?
HTTP 与 HTTPS 的区别
核心区别
| 特性 | HTTP | HTTPS |
|---|---|---|
| 安全性 | 明文传输,无加密 | 通过 SSL/TLS 加密数据,防窃听和篡改 |
| 默认端口 | 80 | 443 |
| 协议栈 | HTTP → TCP | HTTP → SSL/TLS → TCP |
| 证书 | 无需证书 | 需 CA 颁发的数字证书,验证服务器身份 |
| 性能 | 无加密开销,理论更快 | 加密/解密带来轻微延迟(现代优化后影响小) |
| 浏览器标记 | 标记为“不安全” | 显示安全锁图标 |
| SEO | 无优势 | 搜索引擎优先索引 |
详细说明
-
加密机制
- HTTPS 使用混合加密:
- 握手阶段:非对称加密(如 RSA)交换密钥。
- 传输阶段:对称加密(如 AES)加密数据。
- HTTPS 使用混合加密:
-
应用场景
- HTTP:静态内容(如新闻、博客)。
- HTTPS:登录、支付、隐私数据(如银行、电商)。
-
风险提示
- 即使启用 HTTPS,若页面内混用 HTTP 资源(如脚本、图片),仍会触发浏览器警告(Mixed Content)。
为什么选择 HTTPS?
- 用户信任(避免“不安全”提示)。
- 符合 GDPR 等隐私法规要求。
- 防止运营商劫持或广告注入。
TCP 和 UDP 的区别
TCP 提供面向连接的(三次握手)、可靠的(序列号、确认应答、超时重传)数据传输。
UDP 提供无连接的、尽最大努力的数据传输服务
- 传输速率 TCP 要建立连接和维护可靠性机制,传输速率相对较低
- 流量控制
TCP 有流量控制和拥塞控制机制,能根据网络状态调整传输速率
UDP 没有流量控制,以固定速率发送数据 - 通信模式
TCP 支持点对点通信
UDP 支持一对一、一对多、多对多、多对一 - 首部开销
TCP 首部较大,至少 20 字节
UDP 首部 8 字节 - 应用场景
TCP (高可靠传输):HTTP、FTP、SMTP
UDP (高实时性):视频会议、游戏、DNS 查询
TCP 流量控制机制
TCP流量控制是一种端到端的协调机制,主要目的是防止发送方发送数据过快,导致接收方来不及接收处理,从而造成数据丢失。其核心是解决发送方与接收方速度不匹配的问题,确保接收方的缓冲区不会溢出。
滑动窗口机制:
- 接收窗口(rwnd)
接收方通过TCP头部中的Window字段告知发送方自己当前可用的缓冲区空间大小(单位字节) - 发送窗口
发送方实际可发送的数据量取接收窗口和自身拥塞窗口(cwnd)的较小值 - 动态调整
当接收方应用程序读取数据后,接收窗口会增大并通过ACK通知发送方;当接收方处理不及时导致缓冲区填满时,会减小窗口值甚至设为0
关键问题
零窗口死锁问题
- TCP 使用持续计时器,发送方定期发送 1 字节 的窗口探测报文查询最新窗口大小
糊涂窗口综合征
- 问题描述:
当接收方频繁通告小窗口时,会导致大量小包传输,降低效率 - 解决方案:
Nagle算法(发送方累积小数据)或接收方延迟通告小窗口
浏览器
Session、Cookie、Token 的区别
Cookie:
存储在客户端的小型文本文件(通常<=4KB)
服务器通过 Set-Cookie 响应头设置,浏览器后续请求自动携带
可能被 XSS 或 CSRF 攻击窃取,可通过HttpOnly、Secure等属性提升安全性
不可跨域(除非设置domain)
保持用户登录状态、记住用户偏好设置等
Session:
存储在服务端,客户端仅保存 Session ID
服务器创建会话并生成唯一Session ID返回给客户端,客户端后续请求携带此ID
相对安全(数据在服务端),但需防范Session ID泄露
分布式环境下需要特殊处理(如Session共享)
需要跟踪用户状态的场景,如购物车、表单提交等
Token:
存储在客户端(如LocalStorage、Cookie或移动端本地存储),服务端不保存Token本身
服务器验证用户身份后生成Token返回,客户端后续请求在Header中携带此Token
通常使用加密技术生成,较安全,但一旦签发难以主动失效
API访问控制、单点登录(SSO)等
SSL/TLS协议
SSL,Secure Sockets Layer
主要用于解决 HTTP 明文传输的安全风险
TLS,Transport Layer Security
SSL3.0 改进并标准化为 TLS1.0,逐渐取代 SSL
SSL/TLS协议分为两层:
- 记录协议层
作用:对上层数据分块、压缩、加密,并附加MAC值保证完整性
加密方式:采用对称加密(如AES)结合CBC模式,初始化向量(IV)由主密钥生成。 - 握手协议层
TLS握手流程
- ClientHello
客户端发送支持的TLS版本、随机数(Client Random)、密码套件列表(如TLS_AES_256_GCM_SHA384)和压缩方法 - ServerHello
- 密钥交换与验证
- 完成握手
HTTP
版本改动
| 版本 | 协议层 | 关键特性 | 改进点 | 局限性 |
|---|---|---|---|---|
| HTTP/1.0 | 基于 TCP | - 短连接(每次请求需新建 TCP 连接) - 支持缓存(Expires/Last-Modified) - 无 Host 头字段 | 首次标准化 HTTP 协议,支持多种数据类型(如 HTML、图片) | - 高延迟(频繁连接/断开) - 队头阻塞(请求按顺序处理) |
| HTTP/1.1 | 基于 TCP | - 默认长连接(Keep-Alive) - 管道化传输(理论支持,默认关闭) - 断点续传(Range 头) - Host 头支持虚拟主机 | - 减少 TCP 握手开销 - 支持部分资源请求 | - 响应队头阻塞(服务器按顺序返回) - 明文传输,安全性低 |
| HTTP/2.0 | 基于 TCP + TLS | - 二进制分帧(Header/Data Frame) - 多路复用(单连接并发请求) - 头部压缩(HPACK) - 服务端推送(Server Push) | - 提升传输效率与带宽利用率 - 解决应用层队头阻塞 | - 仍依赖 TCP,存在传输层队头阻塞(丢包重传阻塞所有流) |
| HTTP/3.0 | 基于 QUIC(UDP) | - 基于 UDP 的 QUIC 协议 - 多路复用(独立流,无队头阻塞) - 头部压缩(QPACK) - 0-RTT 快速握手 - 连接迁移(Connection ID) | - 彻底解决 TCP 队头阻塞 - 优化移动网络切换(如 IP 变化不影响连接) - 集成 TLS 1.3 加密 | - 新协议兼容性需逐步完善 - UDP 可能被部分网络设备限制 |
HTTP3 选择了 UDP 的原因
- 解决了 TCP 的局限性
- 队头阻塞
TCP 要求数据包按序到达
UDP 无顺序约束,QUIC 协议通过独立的流实现多路复用,单个流丢包不影响其他流。 - 连接建立延迟
TCP 三次握手+TLS握手
QUIC 基于 UDP 实现 0-RTT 或 1-RTT 握手,显著降低延迟 - 协议僵化
TCP 协议栈内置操作系统内核,升级困难
QUIC 在用户空间实现
- 队头阻塞
- UDP 的灵活性以及 QUIC 的增强
- 可靠性增强
QUIC 通过 包编号、ACK 帧、快速重传,避免了 TCP 的重传模糊。 - 连接迁移
TCP 连接依赖四元组(IP+端口),网络切换要重连
QUIC 用 64 位连接 ID,IP 变化时仍可保持连接 - 内置加密
QUIC 默认集成 TLS 1.3
- 可靠性增强
- 适应现代网络需求
- 移动互联网以及弱网环境
- 多路复用与流优先级
- 绕过中间设备限制
新型传输协议常被防火墙拦截,UDP 广泛兼容,成本低
计算机操作系统
JS
- ECMAScript语法基础
- ECMAScript中的执行上下文
- JavaScript原型链
- 闭包
- ES6 新特性
- EventLoop(概念、输入输出)
- 箭头函数
- this 指向
- Var 变量提升
CSS
- 盒模型
- 弹性盒子
- 垂直居中
- 选择器(类型、权重)
前端工程化
前端工程化是指将软件工程的技术和方法应用于前端开发,通过规范化、标准化和自动化的手段,提高开发效率、保障代码质量并降低维护成本。
核心目标是解决四大问题:
- 开发效率
- 协作规范
- 性能优化
- 质量保障
四大核心支柱:
- 模块化
JS 模块化
CommonJS、AMD、CMD、ESM 等规范,解决全局变量污染、依赖管理问题
CSS 模块化
Sass/Less/Stylus 等预处理器,以及 CSS Module、CSS-in-JS
资源模块化
Webpack等工具将图片、字体也视为模块 - 组件化
- 规范化
代码规范
目录结构
工作流程
文档规范 - 自动化
构建工具 开发辅助
面试()
多次
- JavaScript 类型判断
- 如何判断变量是数组
:key 的作用
:key 是 Vue 中的一个特殊属性,主要用于唯一标识虚拟DOM节点,帮助Vue更高效地更新和渲染DOM。它的主要作用包括:
- 唯一标识元素身份
在列表渲染(v-for)或动态组件切换时,通过key可以精确识别每个节点 - 优化渲染性能
通过key的比较,Vue可以复用已有DOM节点,减少不必要的DOM操作,将算法复杂度从O(n³)优化到O(n) - 保持组件状态
防止在列表更新时组件状态(如表单输入值)被意外重置或错乱 - 正确触发过渡动画
在元素切换时,不同的key能确保Vue重新创建元素而非复用,从而触发过渡效果
不使用 key 的后果:
- 性能下降(无法高效复用)
- 状态错乱
- 渲染异常
使用 index 作为key 的问题:
当新插入的项目不在最后(eg:在开头插入,新插入的项目的 index 为 0, 则会导致后续的 index 都发生变化),无法达到提升渲染性能的目的。
底层原理:
Vue 的虚拟 DOM diff 算法
lingyi
编写的 ts 是怎么转换成 js 的
tsc
原型链
https://segmentfault.com/a/1190000042725370
原型(prototype)
- 对象有__proto__属性,函数有__proto__属性,数组也有__proto__属性,只要是引用类型,就有__proto__属性,指向其原型。
- 只有函数有prototype属性,指向new操作符加调用该函数创建的对象实例的原型对象。
原型链的形成
- person1.toString() 的查找路径为:person1 → Person.prototype → Object.prototype → null
xx
- 跨域
- tcp 和 udp
- https
- 三次握手四次挥手
tx
- vue中的 全局状态管理 和 props之类的父子间通信 的区别
数据被多个无关组件频繁使用时 全局 - 正向代理与反向代理
正向代理是客户端的代理(个人翻墙、企业内网、内容过滤);反向代理是服务器的代理(负载均衡、隐藏服务器、缓存加速) - pinia 和 vuex 的区别
- vuex 只有一个全局store,pinia 可以生成多个独立 store
- vuex 通过 mutations(同步)和 actions(异步)修改状态,结构严格但代码冗长;pinia 直接使用 action 处理同步和异步操作
- pinia 的存储
- cookie 和 localstorage 的区别
- 前端工程化(webpack 打包、减小体积。。。)
- 一句话讲一下 ts 的泛型
是一种创建可复用组件的工具,它允许我们在定义函数、接口或类时不预先指定具体类型,而是在使用时再指定,从而增强代码的灵活性和类型安全性。
清单
模块一:前端八股文与基础内功(校招必问)
这是简历《专业技能》第一段的延伸。大厂一面必然是海量的基础拷问,必须倒背如流。
-
JavaScript 核心执行机制
- Event Loop(事件循环):必须能手撕宏任务(setTimeout/setInterval)与微任务(Promise.then/MutationObserver)的执行顺序。浏览器与 Node.js 事件循环的差异。
- 闭包(Closure):闭包的产生原理(词法作用域)、应用场景(比如你在做 Token 刷新队列时用到的私有变量)、以及闭包引起的内存泄漏与排查。
- 原型与原型链:隐式原型
__proto__与显式原型prototype,如何手写继承(寄生组合式继承)。 - Promise 规范:不仅要会用,最好能手写一个简易版的 Promise,深刻理解
resolve、reject、then的链式调用和状态不可逆。
-
计算机网络与 HTTP 协议
- 状态码:200、301/302、304(协商缓存)、401(未授权,与你的刷新队列强相关)、403、500。
- 浏览器缓存机制:强缓存(Cache-Control、Expires)与协商缓存(ETag、Last-Modified)。
- 跨域问题:为什么会跨域(同源策略)?CORS 原理(简单请求与预检请求 OPTIONS),前端 Vite 代理(Proxy)怎么配的?
-
数据结构与算法
- 重点复习:数组/字符串操作、栈与队列(你的无感刷新就是队列应用)、树的遍历(多级表单和嵌套目标的场景)、以及优先队列/最小堆(MinHeap)(如果有面试官深挖你 DailyUse 的调度机制)。
模块二:框架底座(Vue 3 & TypeScript)
这是你干活的饭碗,面试官考察的是你对 Vue3 的深度理解,而不是仅仅会背 API。
-
Vue 3 核心原理
- 响应式原理:
Proxy配合Reflect是怎么劫持对象的?比起 Vue2 的Object.defineProperty有什么绝对优势(比如监听数组和新增属性)? - Composition API 的精髓:为什么要出组合式 API?(逻辑复用、解决 Mixin 命名冲突与来源不清、更好的 TS 类型推导)。
- 组件间通信:父子通信、依赖注入(Provide/Inject)、事件总线(Event Bus)以及你常用的全局状态管理。
- 响应式原理:
-
TypeScript 高级应用
- 泛型(Generics):在封装 Axios 的 Result Pattern 返回值时(
Promise<Result<T>>),泛型是怎么起作用的? - 接口(Interface)与类型(Type)的区别。
- 工具类型:
Partial,Omit,Pick,Record的实际使用场景。
- 泛型(Generics):在封装 Axios 的 Result Pattern 返回值时(
模块三:工程化、构建与性能(拉开差距的关键)
应届生懂业务的很多,懂工程化的很少。这一块是你的加分项。
-
Vite 与前端构建
- 为什么 Vite 在开发环境比 Webpack 快那么多?(ESM 原生模块热更新、esbuild 预构建)。
- 生产环境 Vite 用什么打包?(Rollup)。
-
代码规范与 CI/CD
- Husky + lint-staged:在
git commit时拦截校验代码规范的原理。 - GitHub Actions:它的基本执行流是什么样的?(监听 push/PR 事件 -> 启动 Runner 容器 -> 执行 actions 脚本)。
- Husky + lint-staged:在
-
Astro 与静态站点生成 (SSG)
- 什么是 SSG?与 SSR、CSR 的根本区别是什么?
- Islands 架构(孤岛架构):Astro 是如何做到 0 JS 首屏,又能在特定区域注入交互逻辑的(Hydration 指令如
client:load、client:visible)?
模块四:全栈思维与 Node.js
这部分对应你的个人项目 DailyUse 和 Digital Biome 中的核心 Node.js 脚本。
-
JWT 鉴权体系(重中之重)
- Access Token 与 Refresh Token 的双 token 机制:为什么不直接把一个 token 过期时间设为一年?Refresh Token 存在哪里最安全(HttpOnly Cookie 还是 localStorage)?
- 无感刷新并发处理:如果有 10 个请求同时 401,你是如何用
isRefreshing锁止队列,然后统一放行的?(这是必考的亮剑题)。
-
Node.js 与流式处理
fs和path的常见操作。- Stream(流):为什么 AI 对话(Chatbot)要用流式响应?(Server-Sent Events / Fetch ReadableStream),它的底层网络机制是什么?
-
数据库与 ORM (Prisma)
- 关系型数据库基本的 JOIN 查询、联合索引。
- 什么是 Repository(仓储)模式?(隔离业务层与数据层,如果把 Prisma 换成 Sequelize,业务代码完全不用改)。
模块五:简历项目“深水区”排雷(实战防守)
针对你的三个神级项目,必须准备好以下话术:
-
针对 DDCC(打印模块重构)
- Q:为什么抛弃
html2canvas?- A:因为截图方案会导致失真模糊,且长表格在截图分页时必定会拦腰截断里面的文字,同时无法做到动态内容(如签名表)在每一页都精准重复。
- Q:讲讲
vue-print-next配合pagedjs的原理。- A:
vue-print-next提取需要打印的 DOM 放进隐藏的iframe里;但原生浏览器的 CSS 分页兼容性极差,所以引入pagedjs拦截排版。它会读取 CSS 的@page规范,在 JS 运行时生成一个个带边界的.pagedjs_page虚拟物理页,并在每页底部 fixed 定位我的签名表。
- A:
- Q:为什么抛弃
-
针对 OLP(跨页状态丢失问题)
- Q:你是怎么解决表格翻页,上一页勾选状态丢失的?
- A:这是因为 Element Plus 表格的数据源在翻页时被替换了。我脱离了组件库,自己在外部维护了全局选中的
ID 数组。每次翻页拿到新数据后,用isSettingSelection布尔锁来暂停监听原生事件,手动将之前选中的行数据回填(toggleRowSelection),完美解决死循环和状态重置。
- A:这是因为 Element Plus 表格的数据源在翻页时被替换了。我脱离了组件库,自己在外部维护了全局选中的
- Q:你是怎么解决表格翻页,上一页勾选状态丢失的?
-
针对 Digital Biome(数据清洗与同步)
- Q:你用 Node.js 同步脚本做了什么清洗?
- A:我用正则把 Obsidian 独有的 Wikilink(如
[[页面]])转换成了标准的 Markdown 链接[页面](url);同时读取文档的 YAML frontmatter 提取目标站点的网址,利用第三方 Favicon 接口下载图标并缓存到本地/public,让首页不需要发几百个网络请求,提升了前端渲染速度。
- A:我用正则把 Obsidian 独有的 Wikilink(如
- Q:你用 Node.js 同步脚本做了什么清洗?
100个QA
为了让你在接下来的校招和面试中拥有绝对的统治力,我为你精心准备了 100 道高频、高质量的面试 QA(问答)。
这 100 题严格基于你的简历技术栈(Vue 3、TS、Node.js、工程化、网络、全栈项目实战)划分。建议你每天过 20 题,把它当做你的终极面试复习宝典。
第一部分:JavaScript & TypeScript 内功篇 (1-20)
1. let、const 和 var 的区别?
答: var 存在变量提升且没有块级作用域;let 和 const 有块级作用域,存在暂时性死区;const 声明必须赋值且引用的内存地址不可变。
2. 箭头函数和普通函数的区别?
答: 箭头函数没有自己的 this,它的 this 继承自外层词法作用域;不能作为构造函数;没有 arguments 对象。
3. 什么是闭包?有什么优缺点?
答: 闭包是指有权访问另一个函数作用域中变量的函数。优点是能实现数据私有化(如封装拦截器变量);缺点是使用不当会导致变量无法被垃圾回收,造成内存泄漏。
4. 谈谈你对原型和原型链的理解?
答: 每个对象都有 __proto__ 属性指向它的构造函数的 prototype。当访问对象属性时,如果自身没有,就会顺着 __proto__ 一直向上查找,这就构成了原型链,终点是 null。
5. new 操作符究竟做了什么?
答: 创建一个空对象;将空对象的 __proto__ 指向构造函数的 prototype;将构造函数的 this 指向这个新对象并执行;返回新对象。
6. Promise 有几种状态?
答: 三种:Pending(进行中)、Fulfilled(已成功)、Rejected(已失败)。状态一旦改变就不可逆转。
7. Promise.all 和 Promise.race 的区别?
答: all 等待所有 Promise 成功才成功,一个失败就直接失败;race 是哪个 Promise 最先出结果(不论成功失败),就返回哪个结果。
8. async/await 的原理是什么?
答: 它是 Generator 函数的语法糖,内置了执行器。把异步代码以同步的方式书写,await 后面跟着一个 Promise,会交出执行权,等 Promise 决议后再恢复执行。
9. Event Loop(事件循环)中宏任务与微任务的区别?
答: 宏任务(setTimeout/setInterval)由宿主环境发起,微任务(Promise.then/MutationObserver)由 JS 引擎发起。当前执行栈空了后,会先清空所有微任务,再执行下一个宏任务。
10. 防抖(Debounce)和节流(Throttle)的区别?
答: 防抖是“n秒内只执行最后一次”(如搜索框);节流是“n秒内无论触发多少次,只执行一次”(如滚动事件)。
11. 深拷贝和浅拷贝的区别?如何实现深拷贝?
答: 浅拷贝只拷贝一层引用;深拷贝拷贝彻底,新旧对象互不影响。实现方式有:JSON.parse(JSON.stringify(obj))(有缺陷),或手写递归函数。
12. Map 和 WeakMap 的区别?
答: WeakMap 的键只能是对象,且是弱引用,只要外部对象被销毁,WeakMap 中的键值对也会被垃圾回收器清除,适合做 DOM 节点的元数据存储。
13. TS 中 type 和 interface 的区别?
答: interface 主要用于定义对象结构,支持声明合并;type 是类型别名,可以定义基础类型、联合类型、元组等。
14. TS 中的泛型(Generics)是什么?
答: 泛型是指在定义函数、接口或类时不预先指定具体的类型,而在使用的时候再指定类型的特性。相当于类型的“参数”。
15. any 与 unknown 的区别?
答: any 完全放弃类型检查;unknown 是安全的 any,在对 unknown 类型进行操作前,必须进行类型收窄(断言或判断)。
16. 说几个 TS 常用的工具类型?
答: Partial<T>(属性全变可选)、Pick<T, K>(挑出指定属性)、Omit<T, K>(剔除指定属性)、Record<K, T>(构造对象类型)。
17. typeof 与 instanceof 的区别?
答: typeof 返回数据类型的字符串(对 null 会返回 object);instanceof 用于检查构造函数的 prototype 是否出现在某实例对象的原型链上。
18. 数组去重有哪些方法?
答: 最简单的是 […new Set(arr)];或者使用 filter 配合 indexOf;复杂对象数组需用到 reduce 或 Map。
19. call、apply、bind 的区别?
答: 都是改变 this 指向。call 传散列参数并立即执行;apply 传数组参数并立即执行;bind 传散列参数,不立即执行,而是返回一个新函数。
20. JS 垃圾回收机制?
答: 主要采用“标记清除”法(标记所有内存中可达的对象,清除不可达的)。V8 引擎采用分代回收(新生代用 Scavenge 算法,老生代用标记清除和标记压缩)。
第二部分:Vue 3 与 前端框架篇 (21-40)
21. Vue 3 相比 Vue 2 最大的优势是什么?
答: 引入了 Composition API(更好组织逻辑)、基于 Proxy 重写了响应式(解决了属性添加/删除无法监听的问题)、更好的 TS 支持、按需编译使打包体积更小。
22. ref 和 reactive 的区别?
答: ref 可定义基本数据类型和引用类型,底层用 getter/setter,访问需加 .value;reactive 只能定义对象/数组,底层用 Proxy,不能直接解构(会失去响应式)。
23. 说一下 Vue 3 的响应式原理?
答: 核心是 Proxy 配合 Reflect。通过 Proxy 拦截对象的读取(收集依赖 track)和修改(触发更新 trigger)。
24. watch 和 watchEffect 的区别?
答: watch 需要显式指定监听源,可拿到新旧值,默认惰性执行;watchEffect 自动收集内部依赖的变量,一上来就会立即执行一次。
25. <script setup> 语法糖有什么好处?
答: 代码更简洁,不用写 return,引入的组件直接可用,定义的方法和变量在模板中直接可用,更好的 TS 类型推导。
26. Vue 3 有哪些生命周期钩子?
答: onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted。弃用了 Vue2 的 created 系列,直接在 setup 顶层写即可。
27. Vue 3 组件间通信有哪些方式?
答: Props/Emits、Provide/Inject、Pinia 状态管理、模板引用(ref)、插槽(Slot)。
28. Pinia 相比 Vuex 的优势?
答: 移除了 mutations(直接在 actions 中操作),天然支持 TS 类型推导,体积更轻量,没有嵌套的 modules(每个 store 都是独立的)。
29. v-model 在 Vue 3 中有什么变化?
答: 默认绑定的属性名从 value 变成了 modelValue,事件名从 input 变成了 update:modelValue,且支持在一个组件上绑定多个 v-model。
30. keep-alive 的作用?会触发什么生命周期?
答: 用于缓存组件,避免频繁销毁重建。被包含的组件会触发特有的 onActivated(激活时)和 onDeactivated(失活时)生命周期。
31. Teleport 的作用是什么?
答: 可以将组件的 DOM 节点传送到页面的指定位置(如 body 下),非常适合用来做全屏的 Modal 弹窗,避免受到父组件 CSS 的 z-index 或 overflow 影响。
32. nextTick 的原理和作用?
答: Vue 的 DOM 更新是异步的,nextTick 会在 DOM 更新循环结束之后执行延迟回调。原理是利用 Promise 或 MutationObserver 将回调推入微任务队列。
33. 什么是虚拟 DOM(Virtual DOM)?
答: 用 JS 对象来描述真实的 DOM 结构。改变数据时先生成新的 VNode,与旧 VNode 对比(Diff),然后把差异打在真实 DOM 上,减少直接操作真实 DOM 带来的性能开销。
34. 简单讲讲 Vue 的 Diff 算法?
答: 采用同层比较,深度优先。Vue3 引入了静态提升和靶向更新(PatchFlag),只对比带有动态标记的节点,并通过最长递增子序列算法优化了节点的移动效率。
35. 什么是自定义 Hook(Composable)?
答: 利用 Vue3 的组合式 API,将与状态相关的业务逻辑提取到一个纯函数中(一般以 use 开头),实现逻辑的复用,比 Mixin 更清晰。
36. computed 的缓存机制是什么?
答: computed 是基于其响应式依赖进行缓存的。只有当依赖的数据发生改变时,它才会重新计算,否则多次访问直接返回之前的缓存结果。
37. v-if 和 v-show 的区别?
答: v-if 是真正的条件渲染,会进行 DOM 的销毁和重建;v-show 只是简单切换 CSS 的 display 属性。频繁切换用 v-show。
38. 前端路由的 hash 和 history 模式原理?
答: hash 模式通过监听 hashchange 事件实现,URL 带 #;history 模式基于 HTML5 的 pushState 和 replaceState,不带 #,但需要 Nginx 配置重定向防止 404。
39. Vue Router 有哪些导航守卫?
答: 全局守卫(beforeEach, afterEach)、路由独享守卫(beforeEnter)、组件内守卫(beforeRouteEnter, beforeRouteLeave)。
40. React Hooks 与 Vue Composition API 的区别?
答: React Hooks 每次渲染都会重新执行整个函数,严重依赖依赖数组(deps);Vue 组合式 API 的 setup 只执行一次,状态响应式更新,不用关心闭包陷阱。
第三部分:计算机网络与浏览器原理篇 (41-55)
41. 详细说说 TCP 三次握手?
答: 第一次客户端发送 SYN 报文;第二次服务端返回 SYN+ACK 报文;第三次客户端发送 ACK 报文,连接建立。(作用是确认双方的接收与发送能力正常)。
42. TCP 挥手为什么是四次?
答: 因为 TCP 是全双工的。服务端收到客户端的 FIN(我要关了)后,可以先回 ACK(知道了),但可能还有数据没发完,等发完后再发 FIN 给客户端,所以多了一次。
43. HTTP/1.1 与 HTTP/2 的区别?
答: HTTP/2 引入了多路复用(解决队头阻塞)、二进制分帧、头部压缩(HPACK)、以及服务器推送。
44. HTTPS 工作原理?
答: HTTPS = HTTP + SSL/TLS。结合了非对称加密(交换密钥)和对称加密(实际数据传输),并通过数字证书确保服务器身份的合法性。
45. 常见的 HTTP 状态码有哪些?
答: 200(成功), 301(永久重定向), 302(临时重定向), 304(使用缓存), 400(客户端请求错误), 401(未授权/Token失效), 403(禁止访问), 404(未找到), 500(服务器内部错误)。
46. GET 和 POST 的区别?
答: GET 参数在 URL 中,有长度限制,常用于获取数据,幂等;POST 参数在 Request Body 中,无限制,常用于提交数据,非幂等。
47. 什么是跨域?如何解决?
答: 浏览器的同源策略限制了协议、域名或端口不一致的请求。解决:后端配置 CORS(设置 Access-Control-Allow-Origin),或前端开发环境配置代理(Proxy)。
48. 强缓存与协商缓存的判断流程?
答: 浏览器先看强缓存(Cache-Control/Expires),没过期直接用;如果过期了,带上 ETag 或 Last-Modified 发给服务器协商,服务器如果认为没变就返回 304,否则返回 200 和新数据。
49. Cookie、sessionStorage、localStorage 的区别?
答: Cookie 会被带在每次请求头中,容量约4K;localStorage 永久存储,容量5M+;sessionStorage 关闭标签页即失效。
50. Token 存在哪里最安全?
答: 存在 localStorage 容易受 XSS 攻击被窃取;存在 HttpOnly Cookie 中不能被 JS 读取,能防止 XSS,但需防范 CSRF(通常结合 CSRF Token 解决)。
51. 从输入 URL 到页面渲染的过程?
答: DNS解析 -> TCP三次握手 -> 发送HTTP请求 -> 服务器响应 -> 浏览器解析 HTML 构建 DOM 树,解析 CSS 构建 CSSOM 树 -> 两者合成渲染树 -> 布局(Layout) -> 绘制(Paint)。
52. 重绘 (Repaint) 与回流 (Reflow) 的区别?
答: 回流是指元素的大小、位置发生改变,浏览器重新计算布局;重绘是指元素外观(如颜色)改变,不影响布局。回流必引起重绘,重绘不一定引起回流。
53. 前端如何优化首屏白屏时间?
答: 路由懒加载、图片懒加载、CDN 分发静态资源、开启 Gzip 压缩、使用骨架屏(你在简历里提到了)、提取公共库等。
54. 什么是 XSS 攻击?怎么防御?
答: 跨站脚本攻击,黑客在页面注入恶意脚本。防御:永远不要相信用户输入,进行字符转义(Escape),开启 CSP 内容安全策略,Cookie 设置 HttpOnly。
55. 什么是 CSRF 攻击?怎么防御?
答: 跨站请求伪造,利用用户已登录的身份在钓鱼网站发请求。防御:验证 Referer 字段,请求时附带不可伪造的 CSRF Token,设置 Cookie 的 SameSite 属性。
第四部分:全栈、Node.js 与业务基建篇 (56-70)
56. Node.js 的事件循环与浏览器的区别?
答: Node.js 的事件循环分为多个阶段(Timers, IO callbacks, Idle, Poll, Check, Close),而浏览器主要是一轮一轮的宏任务微任务交替。
57. CJS (CommonJS) 和 ESM 的区别?
答: CJS 是同步加载,输出的是值的拷贝(require / module.exports);ESM 是编译时输出接口,输出的是值的引用(import / export),支持 Tree Shaking。
58. Node.js 中的 Stream(流)有什么好处?
答: 流可以分片处理大文件,避免将整个文件加载到内存导致内存溢出。你在大模型(AI Chatbot)应用中用流式接收,可以实现打字机效果。
59. RESTful API 的核心设计原则是什么?
答: URL 只表示资源(名词),不用动词;使用 HTTP 动词表示操作(GET 查, POST 增, PUT/PATCH 改, DELETE 删);无状态通信。
60. JWT 的构成是什么?
答: 分为 Header(头部)、Payload(载荷/数据)、Signature(签名)。签名由 Header、Payload 加上服务器秘钥(Secret)通过算法生成,防篡改。
61. 为什么全栈项目需要 Refresh Token?
答: Access Token 泄露风险大,所以过期时间短;Refresh Token 专门用来静默刷新 Access Token,提升安全性同时保证用户体验。
62. (简历重点) 你是如何处理无感刷新 Token 的并发请求的?
答: 利用 isRefreshing 变量做锁,第一个 401 请求发起刷新并上锁;后续 401 请求将自身的 resolve 放入队列;刷新成功后,遍历执行队列重新发请求。
63. 什么是仓储模式(Repository Pattern)?
答: 介于业务逻辑层和数据访问层之间。它将数据库查询(如 Prisma 操作)封装起来,业务层只调用仓储层的方法。好处是解耦,未来更换数据库引擎不影响业务逻辑。
64. Prisma 相比传统 ORM 有什么优势?
答: 强类型支持极佳,提供 Prisma Studio,Schema 定义清晰(一个 prisma 文件即可定义数据表、外键及级联关系)。
65. 数据库的左连接 (LEFT JOIN) 和内连接 (INNER JOIN) 区别?
答: 内连接只返回两表匹配的行;左连接返回左表的所有行,如果右表没匹配上则显示 NULL。
66. 什么是数据库的联合索引?
答: 在数据库的两列或多列上建立的索引。遵循“最左前缀原则”,可以极大地优化多条件复合查询的效率。
67. 数据库事务的 ACID 特性是指什么?
答: Atomicity(原子性,同生共死)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)。
68. WebSocket 与 HTTP 的区别?
答: HTTP 是无状态、单向(客户端发)的;WebSocket 握手后建立持久的 TCP 连接,是全双工通信,服务端可主动推数据。
69. SSE (Server-Sent Events) 是什么?
答: 基于 HTTP 的单向通信机制,服务器向客户端单向推送事件数据(MIME 类型为 text/event-stream),是做 AI 流式对话的最佳方案。
70. 什么是 BFF(Backend For Frontend)层?
答: 服务于前端的后端层(一般用 Node.js 写)。用于聚合微服务的接口、清洗数据、裁剪字段,让前端拿到刚好适合渲染的数据格式。
第五部分:工程化、Vite 与部署 DevOps 篇 (71-85)
71. Vite 为什么比 Webpack 启动快?
答: Webpack 启动时需要把所有模块打包成一个 Bundle;Vite 依赖浏览器原生 ES Modules,按需编译当前路由所需的模块,启动近乎零耗时。
72. Vite 的依赖预构建机制是什么?
答: 首次启动时,Vite 会用 esbuild 把项目里的 CommonJS/UMD 依赖转换为 ESM 并缓存,解决了第三方包不支持 ESM 和请求过多的问题。
73. Webpack 和 Rollup 的核心定位区别?
答: Webpack 适合打包庞大的业务应用,支持代码分割和静态资源处理;Rollup 打包产物更纯粹,极其适合打包第三方 JS 库或组件库。
74. Husky 和 lint-staged 是干什么用的?
答: Husky 用于劫持 Git Hooks(如 pre-commit);lint-staged 配合 Husky,只对暂存区(Git Add)的代码运行 ESLint/Prettier,保障提交规范。
75. ESLint 和 Prettier 的分工?
答: ESLint 负责检查“代码质量”(如不用 var、未使用的变量);Prettier 只负责“代码格式化”(如缩进、单双引号)。
76. 什么是 CI/CD?
答: 持续集成(Continuous Integration)和持续交付/部署(Continuous Deployment)。代码推送后自动触发测试、构建和部署,取代人工操作。
77. 简述 GitHub Actions 的基本概念?
答: 它是一个自动化流工具。包含 Workflow(工作流配置文件 yml)、Event(触发事件如 push/pr)、Job(任务)和 Step(具体执行的命令)。
78. 前端项目如何实现多环境隔离?
答: 建立 .env.development、.env.production 等文件。在 Vite 中通过 import.meta.env 注入变量,打包时根据指定的 mode 读取不同配置。
79. SSR、SSG、CSR 的区别?
答: CSR 客户端渲染(全靠 JS 绘图,首屏慢);SSR 服务端渲染(每次请求都在 Node 侧生成 HTML,利于 SEO);SSG 静态站点生成(构建阶段直接生成好所有静态 HTML)。
80. Astro 框架在前端生态中的核心优势是什么?
答: 它天生支持内容驱动的静态网站构建。主打“0 JS”首屏加载(将 JS 剥离),且支持混合使用 React/Vue/Svelte 组件。
81. 什么是 Islands(孤岛)架构?
答: 大面积页面是纯静态 HTML,只有需要交互的部分(如深色模式开关、评论区)才像“孤岛”一样加载 JS 水合(Hydration)。极大提升了页面性能。
82. 简述 Docker 镜像和容器的关系?
答: 镜像(Image)是静态的只读模板(类似于类);容器(Container)是镜像的运行实例(类似于对象),容器内带有完整的运行环境。
83. 为什么要写 Docker 多阶段构建(Multi-stage Build)?
答: 第一阶段包含打包环境(如 Node+pnpm 打包出 dist),第二阶段只用极简的 Nginx 镜像并拷贝 dist。这样最终镜像不包含源码和依赖,体积小且安全。
84. 什么是正向代理与反向代理?
答: 正向代理代理客户端(如翻墙梯子,服务器不知道真正的客户端);反向代理代理服务端(如 Nginx 负载均衡,客户端不知道请求的具体是哪台机器)。
85. Vue 单页应用部署在 Nginx 时,为什么刷新会 404?怎么解决?
答: 因为只有一个 index.html,路径都是前端虚拟路由,服务端找不到真实文件。解决:Nginx 配置 try_files $uri $uri/ /index.html;,将 404 定向回入口文件。
第六部分:你的简历实战深水区 (86-100)
86. (DDCC项目) 为什么重构打印模块时,要抛弃 html2canvas?
答: 截图方案会导致文字发虚;面对长表格分页时会从字中间“拦腰截断”;并且无法优雅地实现在每一页都重复渲染相同的页脚(签名表)。
87. (DDCC项目) pagedjs 的核心原理是什么?
答: 原生 CSS 的打印分页各浏览器兼容性极差。pagedjs 充当了 Polyfill,它读取 CSS @page 规范,在 JS 内存中进行数学计算,动态生成一个个物理尺寸的隔离容器进行精准排版。
88. (DDCC项目) 如何实现动态签名表在打印的每页底部固定重复?
答: 利用 @media print 媒体查询,给签名表加上 position: fixed; bottom: 0;,浏览器打印引擎会在每一张纸上都渲染这个 fixed 元素。
89. (OLP项目) 你的 AI 知识生成模块,是如何接收流式数据的?
答: 调用 fetch 后拿到 Response.body,它是一个 ReadableStream。通过 getReader() 逐步读取 Chunk 数据,再用 TextDecoder 解码拼接到视图变量上,实现打字机效果。
90. (OLP项目) 后台管理系统的分页表格,跨页选中状态丢失的原因是什么?
答: 大部分 UI 组件库的表格默认只维护当前页的数据源。一旦请求下一页接口,数据源被替换,之前的选中状态引用就会被清理。
91. (OLP项目) 解决状态丢失时,为什么要设计一个 isSettingSelection 的布尔值锁机制?
答: 当我们跨页回来,用代码手动触发表格的“勾选(回填)”方法时,会意外触发组件库原生的 selection-change 事件,导致我们自己维护的全局数组被错误清空。加锁可以避开原生事件的死循环干扰。
92. (Biome项目) Astro 项目配合 Pagefind 是怎么实现极速纯静态搜索的?
答: 它不需要后端数据库。在 Astro 构建输出静态文件(dist)后,Pagefind 读取这些 HTML,预先建立索引分块。前端搜索时直接请求极小的分块文件实现毫秒级响应。
93. (Biome项目) 你的 Node.js 脚本是怎么解析 Markdown 中的 Obsidian 双链的?
答: 引入 Node 的 fs 模块读取文本,编写正则表达式 匹配 \[\[(.*?)\]\],利用 replace 方法将内部的链接名提取出来,重写为标准的 Markdown [name](name) 格式。
94. (Biome项目) 为什么要把获取 Favicon 这样的操作写在 Node.js 同步脚本里,而不是前端去发请求?
答: 如果前端在导航页向第三方接口发几百个获取图标的请求,会严重阻塞渲染且触发接口限流。在 Node 层构建时清洗并缓存到本地,前端直接读同源静态文件,性能实现了质的飞跃。
95. (DailyUse全栈) 你封装 Axios 时的 Result Pattern(结果模式)解决了什么业务痛点?
答: 传统写法,任何 400/500 的 HTTP 错误都会抛出异常,前端必须写无数个冗余的 try-catch,一旦漏写就会白屏。我拦截所有异常,统一包装为 { ok: false, error },让业务逻辑如丝般顺滑。
96. (DailyUse全栈) 面对巨型表单,你是怎么做组件拆解的?
答: 我打破了单一文件的写法,按照“基础信息”、“时间配置”、“高级规则”切分成多个独立的业务组件。子组件绝不直接修改 props 数据,而是统一 emit 事件向上流转。
97. (DailyUse全栈) 既然拆散了组件,你是怎么解决“父组件怎么知道表单全填对了”这个验证难题的?
答: 我提取了一个专属的自定义 Hook。里面管理着各个子模块的验证状态变量,最终暴露出一个汇总的 computed 属性 isFormValid。实现了验证逻辑的聚合与视图的解耦。
98. (DailyUse后端) 在 Prisma 建表时,你提到了 Cascade(级联),这是解决什么问题的?
答: 比如任务表和评论表是一对多,如果在 Schema 中配置了外键的 onDelete: Cascade,当我在数据库删除这条任务时,底层会自动删除所有与之关联的评论,防止产生垃圾孤儿数据。
99. (DailyUse实战) 什么是单向数据流?它在你的全栈项目中有什么体现?
答: 数据只能从父组件流向子组件,子组件不能直接修改父组件传来的数据。在我的拆分组件中体现为:数据属于父级,子级只负责“展示”和“通知父级去改”,保证了数据变更追踪的可控性。
100. (综合送分题) 你觉得在公司实习(如 OLP/DDCC)和你自己搞独立开源项目(DailyUse/Biome),最大的区别是什么?
答: 实习让我学会了在既定框架内工作、遵守 Git 分支流和企业级代码规范,懂得了业务妥协和跨部门沟通;而自己做全栈项目则逼迫我站在”架构师”的视角从 0 思考选型、数据库设计和 CI/CD 闭环,两者结合让我既具备大局观,又拥有极强的落地执行力。
📖 相关资源
- frontend-interview-high-frequency-moc - 前端高频面试题
- algorithm-interview-patterns-moc - 算法面试题型
- interview-cs-fundamentals-moc - 计算机基础面试
AI 工程师面试复盘
核心教训
AI 工程师面试最吃亏的不是”没做过”,而是”说不清工程细节”。面试官会逐层追问,验证你是否真的能独立落地。
最常见的扣分模式
- 说到关键词就停:说了”状态机""Schema 校验""重试”,但没继续讲状态有哪些、数据结构怎么设计、重试条件是什么
- 回答停留在概念层:面试官问实现细节,回答”可以用现成库""让 AI 帮我规划”
- TypeScript 类型能力偏弱:
as type断言不是类型安全,泛型 + 条件类型才是正解
每个回答应该覆盖的层次
状态有哪些?数据结构怎么设计?失败怎么处理?重试条件是什么?怎么防止重复执行?代码层面用什么库?怎么观测效果?
关键知识点速查
| 主题 | 新笔记 |
|---|---|
| Function Calling 参数校验 | function-calling-parameter-validation-and-retry |
| SSE 流式暂停与中断 | sse-streaming-pause-and-cancel |
| 多模型 Provider 抽象 | multi-model-llm-provider-abstraction |
| 首字延迟全链路优化 | ai-assistant-first-token-latency-optimization |
| Token 成本优化 | llm-token-cost-optimization-strategies |
| TypeScript 高级类型 | typescript-advanced-types |
自我介绍模板
我是 XX 专业 XX 届毕业生,主要技术栈是 TypeScript、Node.js、React/Vue,前后端都有项目经验。最近比较核心的项目是 XX,我主要负责从产品方案、前后端开发、AI 能力接入、测试、CI/CD 到云服务器部署的完整链路。
项目表达结构(STAR)
- Situation:背景是什么
- Task:我负责什么
- Action:技术难点是什么,我怎么解决
- Result:最终效果是什么,如果重构会怎么做