# 25. 华为od面试2026
# 1. 类似牛客网的机试
有智能补全,选 JavaScript Node 后会给一个输入输出的例子。而且已经不是 readline 模式了,和 leetcode 差不多了,需要 return 返回。
最后260分。1、2题共200分,3题不会,用例过了30% 60分。
# 2. 性格测试
参考之前的 od 面试 105 题(性格测试),不限制时间。
# 3. hr资格面
# 3.1 面试问题清单
- 自我介绍
- 各个公司离职原因
- 工资构成
- 是否有其他 offer
- 英语 4 级为啥没过,只考了一次
- 上家公司有多少人,你带了几个人,负责什么?
- 是否了解华为部门岗位,数字与能源
- 你说领导对你很好,好在哪?
# 3.2 自我介绍(模板)
面试官您好,我是 XXX,XX 大学 XX 专业,前端开发 X 年。 工作经历一共 5 段:前两段分别在公路工程行业信息化和地图可视化方向,先把前端基础打扎实了;中间在腾讯子公司做 toB 业务,主要是工单管理平台和坐席 AI 智能助手 SDK;最近一段在华胜天成继续做前端开发。 技术上主要以 Vue 2 / Vue 3 + TypeScript 为主,熟悉 Webpack / Vite 工程化、性能优化、WebSocket 实时通信,也做过地图可视化相关业务(实时位置、历史轨迹、报警联动)。 我最近讲得比较多的项目是用 Vue 3 写的一个坐席 AI 智能助手前端 SDK,第三方呼叫中心系统引入一个 script、调一次 init 就能接进去,通话中通过 WebSocket 接收实时 ASR 字幕、AI 通话小结、实时质检等多路消息。 我个人的特点是比较能扛压、上手快,这次希望找一个业务稳定、能长期做下去的平台,所以特别希望能加入华为。
# 3.3 离职原因
第一份:公路工程公司(毕业后的第一份)
毕业后我花了一段时间想清楚职业方向。当时先进入公路工程行业做信息化相关的工作,在这个过程中发现自己对前端技术开发更有热情,也更想往互联网技术方向发展。所以经过慎重考虑,我决定转向前端方向,为此做了系统学习和项目准备。
注意:不要说是"没想好随便去的",要包装成"探索期后明确方向"。
第二份:武汉地大公司
在这家公司我主要负责地图相关的前端开发,领导和工作氛围都很好。但技术栈相对传统,我希望能接触到更主流、更新的前端技术体系,提升自己的技术竞争力,所以选择了离开。这段经历让我打下了扎实的前端基础,也让我更清楚自己要往哪个方向走。
第三份:上海上讯
上讯离开是因为我当时非常想去更大的平台发展,接触更高复杂度的业务和更成熟的技术体系,所以选择了腾讯的机会。
第四份:腾讯(子公司)
腾讯这段经历让我学到了很多,尤其是大厂的技术规范和协作流程。后来因为公司内部业务调整,降本增效,西安、长沙、上海的组都被砍掉了。
第五份:华胜天成
华胜天成也是因为公司内部业务调整,业务不稳定,西安和上海整个团队都被裁撤了。这两段经历让我更加希望找一个业务稳定、平台大、能长期发展的公司,所以华为是我的首选。
所有离职原因归为"个人发展"或"业务调整",所有回答指向"我想在华为长期稳定发展,能扛压、能加班、能快速上手"。
# 3.4 为什么来华为?
主要有三个原因:
- 华为是我一直很认可的平台,技术积累深、业务稳定、体系成熟,能让我长期深耕;
- 我有朋友在华为,了解到这边虽然节奏快、要求高,但成长也很快,我希望能在这种环境里提升自己;
- 我之前的经历里有几段是因为公司业务调整被动离开,所以我现在更看重平台的稳定性和长期发展空间,华为正好符合我的诉求。
# 3.5 华为能给你带来什么?你能给华为创造什么价值?
华为能给我带来的是:更大的技术平台、更规范的研发流程、更高复杂度的业务场景,以及持续学习和成长的机会。
我能给华为带来的是:
- 扎实的前端开发能力,能快速上手业务;
- 多段不同公司的经历,让我适应能力比较强,能快速融入团队;
- 我做过多段不同业务,技术面比较广,能应对不同需求;
- 我抗压能力强,愿意加班投入,能保证交付。
# 3.6 职业规划
- 短期(1-2 年):快速熟悉华为的业务和技术栈,成为团队里能独立承担模块开发的人;
- 中期(3-5 年):在前端领域深耕,往技术专家或技术骨干方向走,能带小团队或负责核心模块;
- 长期:希望在华为长期发展,跟着平台一起成长。
注意:不要说"想转管理"或"想创业",华为OD更看重你能不能踏实干活。
# 3.7 如何看待加班?(压力面)
我理解华为的节奏,也做好了心理准备。我之前在腾讯和华胜天成的时候,也有过项目紧张期加班的情况,我是能接受的。我认为加班是为了保证项目交付,只要是有目标、有节奏的加班,我是愿意配合的。当然,我也会尽量提升效率,减少不必要的加班。
注意:不要问"加班多不多",不要表现出犹豫。
# 3.8 工资构成怎么答?
先把结构说清楚,再给期望值,不要只甩一个月薪数字。
我的构成是:基本工资 + 绩效工资 + 年终奖(X 个月)+ 补贴(餐补 / 交通 / 话补)+ 加班费或调休,公积金按 X% 缴,社保公积金基数按实/按最低。目前税前月薪 X,年包大概 X 万(含年终和补贴)。
期望上:希望比现在有合理涨幅(市场常见 20%~30%,具体看定级),也希望能了解华为这边的薪资结构和绩效规则。
# 3.9 手里有没其他 offer?
目前没有,刚离职不久,想先全力准备华为的面试。
# 3.10 英语 4 级为啥没过,只考了一次?
在校时精力主要放在专业课和项目上,英语只按应试准备了一次,确实是重视不够,这是我自己的问题,不找客观理由。
但实际工作中英文不是障碍:技术文档、报错信息、GitHub issue、API 文档基本都是英文的,我平时搜索和看源码都在用英文;口语上日常读写没问题。如果岗位有硬性要求,我愿意再考,也会继续补英语。
(要点:承认 + 不贬低自己 + 用工作事实补位 + 给出口。)
# 3.11 是否了解华为部门岗位(数字与能源)?
提前做过功课,可以这样答:
数字能源是华为的重点业务方向之一,围绕清洁发电、能源数字化、交通电动化、站点与数据中心能源基础设施、综合智慧能源这些场景,前端侧主要是能源数字化平台、监控运维系统、数据可视化大屏这类系统——业务属性强、数据量大、对实时性和稳定性要求高。
我的匹配点:
- 做过实时数据链路(WebSocket 长连接 + 多路消息分发 + 断线重连),能应对实时监控类场景;
- 做过地图可视化(实时位置、历史轨迹、报警),可视化大屏类需求上手快;
- 做过 SDK 化交付(嵌入第三方系统、样式隔离、生命周期管理),对接集成类场景有经验。
(要点:先说部门业务方向 → 再说岗位可能的系统形态 → 最后落到自己的可迁移经验。)
# 3.12 你说领导对你很好,好在哪?
从四个角度答,落到"所以我成长快、也愿意跟这样的领导长期干":
- 信任与放权:重要需求敢交给我独立负责,方案让我自己定,只在关键节点对齐,这让我成长很快;
- 愿意给反馈:代码 review 会直接指出问题,需求优先级也会帮我梳理,做错了当场说清楚,不搞"背后评价";
- 替我争取:绩效、调级、好项目机会都会帮团队争取,团队拿结果时他会替大家说话;
- 氛围和担当:需求临时变更、线上出问题,他先挡住压力、再一起解决,不甩锅。
# 3.13 看你之前面过华为 od,最后为啥没来?
当时是先拿到华胜天成的 offer 了,而且业务方向也挺匹配的,所以就去了,入职后才过了华为的 offer,已经入职了想稳定做一段,不想刚去就离职。
# 4. 技术一面
# 4.1 自我介绍
毕业院校、专业、工作经历、项目经历、技术栈(话术见 3.2 自我介绍)。
# 4.2 项目过程中遇到的难题
答"辅助 SDK 的开发需求"(坐席 AI 智能助手前端 SDK),一个主难点 + 一个备选难点:
难点一:把一个 Vue 3 应用做成"可嵌入任意第三方系统的 SDK"
- 生命周期管理:内部用
createApp(App)动态挂载到宿主节点或自建容器,destroy()时要unmount()+ 移除 DOM + 清空引用,否则宿主页面内存泄漏、事件残留; - 样式隔离:CSS 打进 JS 运行时注入,统一加作用域前缀,既不污染宿主也不被宿主干扰;
- 对外 API 设计:只暴露
init / login / logout / destroy+ 白名单事件订阅,内部用事件总线桥接,内外完全解耦; - 资源冲突:z-index 不写死,用全局递增调度,避免和宿主弹窗打架。
难点二:WebSocket 实时链路的可靠性
- "连接假死":
onopen已触发、socket 显示连着,但后端其实断了,不推数据也不触发close,字幕静默消失。解法是自建心跳 ping/pong(连续 5 次没回 pong 主动重连)+reconnecting-websocket自动重连; - 流式字幕时序:整句和半句混着来,要区分"替换当前半句"还是"落一条完整记录",断线期间按
message_id去重。
细节见 16. 面试问题1 (opens new window)。
# 4.3 null 和 undefined 的区别
null 和 undefined 都表示"没有值",但在 JavaScript 中它们的含义、产生方式和典型用途有明显区别。
核心区别一句话:
- undefined 通常是"系统自动给的"——变量声明了但没赋值、函数没返回值、访问不存在的属性等。
- null 通常是"人为主动设置的"——表示"这里 intentionally 就是空"。
1. 含义与语义
- undefined:表示"未定义/缺失",是引擎在缺少值时自动产生的。
- null:表示"空值/无对象",一般由开发者显式赋值,用来清空或占位。
2. 类型
typeof undefined // "undefined"
typeof null // "object" ← 这是 JS 的历史遗留 bug
2
注意 typeof null === "object" 不代表 null 是对象,只是早期实现遗留问题。
3. 常见产生场景
| 场景 | undefined | null |
|---|---|---|
| 变量声明未赋值 | ✅ | ❌ |
| 函数无返回值 / 无 return | ✅ | ❌ |
| 访问对象不存在的属性 | ✅ | ❌ |
| 函数调用未传参 | ✅ | ❌ |
原型链终点 Object.prototype.__proto__ | ❌ | ✅ |
正则 match 无匹配结果 | ❌ | ✅ |
JSON.parse('null') | ❌ | ✅ |
4. 转换与比较(常被追问)
Number(null) // 0
Number(undefined) // NaN
null == undefined // true (宽松相等规则里两者互等)
null === undefined// false
JSON.stringify({ a: null, b: undefined }) // '{"a":null}' → undefined 的键会被丢弃
JSON.stringify([null, undefined]) // '[null,null]' → 数组里 undefined 变 null
2
3
4
5
6
- 默认值只在 undefined 时生效:
function f(a = 1) {},f(null)拿到的是 null,不是 1;解构默认值const { a = 1 } = { a: null }同理。 - 判断方式不同:判断 null 用
x === null;判断 undefined 用typeof x === 'undefined',因为未声明的变量直接用x === undefined会报 ReferenceError。
5. 使用建议
- 需要"显式置空"时用 null(比如释放对象引用、接口约定字段为空);
- 不要给变量手动赋 undefined,交给引擎产生即可;
- 判断"没值"时用
x == null可以一次覆盖 null 和 undefined 两种情况。
# 4.4 vue2 升级到 vue3 的难题
升级过程见 10. vue2迁移到vue3 (opens new window)(完整答案见 5.8),实际遇到的难点集中在:
- 老代码体量大:几千个文件不可能一次重写,只能先跑
@vue/compat兼容构建,把告警按类型分批清掉; - 第三方库不支持 Vue 3:部分老组件库/图表封装没有 Vue 3 版本,只能替换或自己包一层适配;
- 行为差异踩坑:
$children移除、事件总线$on/$off移除(换 mitt)、filter 移除、v-model语义变化、$listeners合并进$attrs、生命周期改名; - 构建链路:
vue-cli/ webpack 配置里 loader、plugin 都要跟着升,顺手迁到 Vite 时环境变量、静态资源引用方式都要改; - 回归成本高:升级后必须靠完整回归 + 自测兜底,所以分模块灰度上线,先非核心页再核心页。
# 4.5 你熟悉的设计模式有哪些
先给一句总述,再"一个模式 + 一个项目里的真实用法",比背定义分高。
| 设计模式 | 在前端 / 项目中的用法 |
|---|---|
| 单例模式 | Pinia/Vuex store、全局弹窗、SDK 实例(init 时加守卫防止重复挂载出双实例) |
| 发布订阅 / 观察者 | Vue 响应式(Dep/Watcher)、事件总线(mitt)、WebSocket 一路 message 分发给字幕/质检/小结多个模块 |
| 策略模式 | 按 msg_type 分发的处理器映射表、表单校验规则,替代一长串 if-else |
| 工厂模式 | 按消息类型/组件类型创建对应的处理器或组件实例 |
| 代理模式 | Vue 3 Proxy 响应式、图片懒加载、防抖节流与接口层的统一封装 |
| 适配器模式 | 不同宿主系统、不同后端字段差异,用适配层统一成内部数据结构 |
| 装饰器 / 高阶函数 | axios 拦截器、unplugin-auto-import 式的语法糖、埋点与日志包装 |
| 模块 / 闭包模式 | SDK 内部状态用闭包私有化,避免污染宿主全局变量 |
| 状态模式 | 通话状态机(待接入 → 通话中 → 挂断)驱动 UI 显示 |
我讲得最多的两个:发布订阅(WebSocket 消息分发 + 事件总线解耦内外)和策略模式(消息类型处理器表,加一种消息只加一个处理器,不改主流程)。
# 4.6 算法题:班委选举
题目: 一次班委选举,导员收集了大家关于班长的投票结果,按照以逗号间隔的方式记录了一组姓名拼音,名字和名字之间逗号隔开,请协助导员统计下候选人的票数,按照票数高低的顺序输出名字空格票数,如果相同票数的情形下按照字母升序输出。
输入
xiaoming,xiaozhang,xiaoli,zhangsan,xiaoming
输出
xiaoming 2, xiaoli 1, xiaozhang 1, zhangsan 1
const input = 'xiaoming,xiaozhang,xiaoli,zhangsan,xiaoming';
function sortHeader(str) {
// 1. 用 Map 统计票数,避免用对象时 __proto__、constructor 这类键名踩坑
const count = new Map();
for (const name of str.split(',')) {
const key = name.trim();
if (!key) continue;
count.set(key, (count.get(key) || 0) + 1);
}
// 2. 票数降序;票数相同时按字母升序
return [...count.entries()]
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
.map(([name, num]) => `${name} ${num}`)
.join(', ');
}
console.log(sortHeader(input)); // xiaoming 2, xiaoli 1, xiaozhang 1, zhangsan 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
原代码的两个问题(容易被面试官追问):
- 票数相同时写的是
a[0] - b[0],字符串相减得到NaN,比较函数结果不确定,排序等于没生效;字符串排序要用localeCompare或a[0] < b[0] ? -1 : 1。 - 返回的是二维数组,而题目要求输出
名字 空格票数用逗号拼接的字符串,需要再map + join一次。
# 5. 技术二面
# 5.1 手撕代码:合并区间
题目: 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。
示例 1
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
2
3
示例 2
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。
2
3
提示
1 ≤ intervals.length ≤ 10^4intervals[i].length == 20 ≤ starti ≤ endi ≤ 10^4
const intervals = [[1, 3], [2, 6], [8, 10], [15, 18]];
function merge(intervals) {
if (!intervals.length) return [];
// 1. 拷贝一份再按起点升序排序,避免修改调用方传入的数组
const arr = intervals.map((item) => item.slice()).sort((a, b) => a[0] - b[0]);
const ans = [arr[0].slice()];
for (let i = 1; i < arr.length; i++) {
const last = ans[ans.length - 1];
const [start, end] = arr[i];
// 2. 当前区间起点大于上一段终点 → 不重叠,直接开新段;否则合并取较大终点
if (start > last[1]) {
ans.push([start, end]);
} else {
last[1] = Math.max(last[1], end);
}
}
return ans;
}
console.log(merge(intervals)); // [[1,6],[8,10],[15,18]]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
复杂度: 排序 O(n log n),遍历 O(n);空间 O(n)(排序 + 结果)。注意点: 判断重叠用 start > last[1](不是 >=),所以示例 2 的 [1,4]、[4,5] 会正确合并成 [1,5]。
原代码的三个问题(面试官一定会看):
- 循环里用的是
intervals.length,但排序后的数组是arr,两个数组不一致(这里长度相同才没出错),应该用arr.length; ans.push(arr[0])、ans.push(arr[i])都是直接塞引用,后续ans[ans.length - 1][1] = ...会改掉入参里的原区间,属于副作用 bug,要slice()或新建数组;- 起始分支用
i === 0特判,不如直接把第一段推进结果再从i = 1开始,少一次判断。
# 5.2 vue2 和 vue3 的差异,为什么用 Proxy
一句话:Vue 2 用 Object.defineProperty 递归劫持每个属性,Vue 3 改成用 Proxy 代理整个对象,解决了 Vue 2 响应式的能力缺陷和初始化性能问题。
Vue 2 的四个痛点(正是换 Proxy 的直接原因)
- 只能劫持已存在的属性:新增 / 删除属性不响应,必须用
Vue.set/Vue.delete; - 数组只重写了 7 个方法(
push/pop/shift/unshift/splice/sort/reverse),arr[0] = x、arr.length = 0这种写法不触发更新; - 初始化时递归遍历对象所有层级,数据再大也要一次性转成响应式,首屏开销大(哪怕这些数据压根没用到);
- 无法劫持
Map/Set/WeakMap/WeakSet等集合类型。
Proxy 的优势
- 代理整个对象,可以拦截
get/set/deleteProperty/has/ownKeys,新增删除属性天然响应式,不再需要$set; - 支持数组索引和
length直接赋值; - 惰性代理:只有真正访问到某个属性时,才把返回的对象递归转成响应式,初始化更快、内存更省;
- 支持
Map/Set等集合类型(内部用一套 collection handlers); - 代价:IE 不支持且没法 polyfill;每次读写多一层 Proxy 拦截,Vue 3 用缓存(
reactiveMap)、shallowRef/markRaw等手段规避额外开销。
其他差异(顺带说,别只答响应式)
- API:选项式 → 组合式(
setup、ref/reactive、显式导入computed/watch),逻辑复用从 mixin 变成组合式函数; - 生命周期:
destroyed→unmounted,beforeDestroy→beforeUnmount; - 编译期性能优化:静态提升、
patchFlag、Block Tree、最长递增子序列求最小移动次数,diff 更快; - 打包体积:支持 Tree-shaking,只打包用到的 API;
- 新特性:Fragment(多根节点)、Teleport、Suspense、
defineComponent; - 破坏性变更:filter 移除、
$on/$off/$once移除(事件总线改 mitt)、$children移除、v-model语义变化、.sync移除、$listeners合并进$attrs; - 工程体验:Vite + TypeScript 支持更好,类型推导和编辑器提示明显更强。
参考:7. vue响应式原理 (opens new window)、17. 面试问题2 (opens new window)。
# 5.3 企点中的"多 set"是什么
背景:当时只有一套测试环境,多个需求并行开发时互相耦合——一个人改的代码会影响别人测试,需求排期互相卡。
目标:把一套测试环境变成多套(set1 ~ set10),不同主号(账号)走不同的 set 环境,需求之间彻底隔离。
做法(本质是"打包部署时多一层目录 + 运行时按账号路由"):
- 部署侧:项目用 Coding 流水线部署,给流水线加
env(环境)和set(第几套)两个参数,往 COS 发资源时路径多拼一层,比如set_2_8,资源就落到服务器上对应的 set 目录; - 访问侧:用户登录后 cookie 里有主号,nginx 匹配静态资源路径时先看 cookie 里有没有
qidian_env_set,有就直接拼到路径上取对应 set 的资源; - 兜底:cookie 里没有时,用 lua 脚本调接口拿到该主号的
env和set,拼接路径并写回 cookie,下次直接命中。
结果:多个需求可以并行在各自的 set 上开发测试,互不干扰。
收获与反思:顺带学会了 lua 在 nginx 里的应用;反思是"多 set"之后账号和 set 的对应关系、每个 set 上跑着哪些需求,必须做台账记录,否则后面找人、找环境会非常乱。
细节见 16. 面试问题1 (opens new window)。
# 5.4 企点中的项目性能优化是怎么做的
按"先量指标,再分层优化"的思路答,分四层说:
1. 指标先行(先说什么叫"快")
- 加载类:FCP(首次内容绘制)、LCP(最大内容绘制)、TTI、首屏时间、资源体积、请求数;
- 交互类:FPS、长任务(long task)、输入延迟;
- 工具:Lighthouse / Performance 面板 /
performance.getEntriesByType('navigation')打点上报。
2. 网络与加载层
- 路由懒加载 + 组件按需引入,控制首屏包体积;
- CDN 加速、gzip/Brotli 压缩、HTTP/2 多路复用;
- 关键资源
preload/preconnect,非关键脚本defer/async; - 静态资源带 hash 走强缓存,HTML 走协商缓存。
3. 渲染层
- 长列表用虚拟滚动 + 分页,避免一次渲染上千个工单节点;
- 动画只用
transform/opacity,避免触发 reflow;批量读写 DOM,减少回流重绘; - 图片懒加载、大图压缩与 CDN 裁剪。
4. 框架与业务层
- Vue:
v-once/v-memo、keep-alive缓存页面、shallowRef/shallowReactive避免大对象深度响应式、computed缓存派生数据; - 实时链路:用 WebSocket 推送替代轮询,减少无效请求;
- SDK 场景:控制产物体积(按需打包、把宿主已有的依赖
externals掉,不重复打包)、样式注入不影响宿主首屏。
(更全的方法清单见 23. 性能优化方法 (opens new window)。)
# 5.5 事件循环是什么
一句话:JS 是单线程的,事件循环(Event Loop)就是"调用栈 + 任务队列"的调度机制——同步代码在栈上跑,异步任务的回调按宏任务 / 微任务分队列排队,栈空了就按规则取出来执行。
执行顺序(背下来):
- 先执行同步代码(主线程调用栈);
- 同步代码执行完 → 清空微任务队列(
Promise.then、queueMicrotask、MutationObserver),期间产生的新微任务也一并清空,直到队列为空; - 从宏任务队列取一个任务执行(
setTimeout、setInterval、I/O、UI 渲染、MessageChannel); - 执行完这个宏任务 → 再清空一次微任务队列;
- 回到第 3 步,循环往复。
口诀:先同步,再微任务,后宏任务;每执行一个宏任务,必清空一次微任务。
经典例题
console.log('1');
setTimeout(() => console.log('2')); // 宏任务
Promise.resolve().then(() => console.log('3')); // 微任务
console.log('4');
// 输出:1 4 3 2
2
3
4
5
加分点
- Node.js 的事件循环还分
timers/pending callbacks/poll/check/close callbacks等阶段,process.nextTick优先级高于 Promise; - 浏览器里渲染(一帧)也是一个宏任务级别的时机,"微任务在渲染前执行"正是
nextTick用微任务的原因(见 5.9); - 微任务如果一直互相递归,会饿死宏任务和渲染,导致页面卡死。
参考:11. 前端面试可能会问到? (opens new window)、17. 面试问题2 (opens new window)。
# 5.6 开发中如何用 AI
核心原则:AI 做执行、我做决策;AI 生成、我 review;最终质量和结果由我负责。落地成一条工作流:
- 规范前置:把团队开发规范、技术栈、组件库约定、命名规范沉淀成 Skills / instructions 给 AI,让 AI 一开始就"懂规矩",减少重复纠正;
- 需求 → 方案:自己先读透需求和边界,再让 AI 输出模块拆分、技术选型、数据结构、风险点,方案我拍板;
- 开发:先让 AI 出骨架 + 类型/接口定义,再按方案逐步实现,每一步确认后再往下;关键用例先让 AI 写测试;
- 还原与联调:Figma MCP 按设计稿生成代码 + mock 数据;接口文档通过 MCP 喂给 AI 按真实字段改代码,避免手抄出错;
- 自测与 BugFix:把报错栈、复现路径、期望行为给 AI 定位问题,但每个 patch 我都会先理解根因再合入;
- 底线:AI 生成 ≠ 可靠(安全、核心逻辑必须人肉把关);AI 不背锅;踩过的坑和有效提示词持续沉淀。
详细版见 22. ai相关问题 (opens new window)。
# 5.7 用 AI 的时候会整理 skill 吗
会,而且我是把 skill 当作"团队规范的可执行版本"在用:
- 沉淀什么:项目的技术栈与版本约定、目录与命名规范、组件库 / 工具函数的用法、接口封装约定、代码风格与提交规范、踩过的坑(比如"这个组件库的 X 属性不要用");
- 放在哪:写成
copilot-instructions.md、.instructions.md、SKILL.md、自定义 agent 或 prompt 模板,随仓库一起走,团队共享; - 好处:AI 一次"懂规矩"后输出天然贴合团队规范,少来回纠正;新人也能直接复用,等于把口口相传的经验文档化;
- 怎么维护:把每次踩的坑、有效的提示词回写到 skill 里,让它越用越准,而不是一次写完不管。
一句话:代码是产物,skill 是把经验变成可复用的生产力。
# 5.8 vue2 如何迁移到 vue3
完整变更清单见 10. vue2迁移到vue3 (opens new window),流程可以这样讲:
1. 准备
- 先升级 Node / 构建工具(
vue-cli或 webpack 相关 loader、plugin),保证工程能跑; - 装
@vue/compat兼容构建,把vue别名指向它,配置compilerOptions.compatConfig,先让老代码在 Vue 3 下跑起来,再看控制台告警。
2. 代码层面(按告警分批改)
- 全局 API:
new Vue()→createApp(),Vue.use→app.use,Vue.prototype.x→app.config.globalProperties.x,Vue.nextTick→ 从 vue 里导入nextTick; - 生命周期:
beforeDestroy/destroyed→beforeUnmount/unmounted; - 事件与通信:
$on/$off/$once移除 → 换mitt事件总线;$listeners合并进$attrs;$children移除 → 用ref或provide/inject; - 模板语法:filter 移除 → 改成方法或
computed;v-model语义变化(多个 v-model、去掉.sync);v-if与v-for优先级反转;插槽统一用v-slot; - 响应式:
Vue.set/delete不再需要,可直接赋值; - 组件:函数式组件改写成普通函数 +
props,emits选项显式声明事件,异步组件改用defineAsyncComponent; - 状态管理:Vuex 可平滑保留,想升级就换 Pinia,
mapState等方式也要跟着改。
3. 渐进式策略(重点,体现工程能力)
- 不要一次重写:先修构建报错 → 再修运行时告警 → 按模块灰度迁移,非核心页先上;
- 用
vue-codemod/ gogocode 自动转换一部分机械性改造,人工只处理逻辑差异; - 每批改动都跑完整回归 + 自测,保证线上不出问题。
4. 收尾
- 全部告警清零后去掉
@vue/compat,享受 Tree-shaking 和编译优化带来的体积 / 性能收益; - 可选迁到 Vite,开发启动和热更新都会明显变快。
# 5.9 vue 中为什么 nextTick 用的是微任务
要分两层答:nextTick 解决什么问题 + 为什么必须是微任务。
1. nextTick 解决什么
Vue 的 DOM 更新是异步批量的:改数据只是把 watcher 推到 scheduler 队列,等到 nextTick(也就是 flushSchedulerQueue)时才真正 patch DOM。所以刚改完数据立刻读 DOM 还是旧值,this.$nextTick(cb) 保证 cb 在本次 DOM 更新之后执行。
2. 为什么用微任务(Promise.then / MutationObserver)
- 时机刚好:微任务在当前宏任务执行完、浏览器渲染之前清空。这样一轮事件循环内就能完成"改数据 → 渲染函数排队 → patch DOM → 回调执行",回调里能拿到最新 DOM;
- 不会多等一轮:如果用宏任务(
setTimeout),DOM 更新会被推到下一轮事件循环,中间浏览器可能先按旧数据绘制一帧,用户会看到闪一下旧数据;同时多等一轮也会让"改数据后马上测量 DOM"的代码变慢、布局跳变; - 不需要等时间:微任务在当前任务末尾自动清空,不用像
setTimeout那样等最小延迟,时效性最好; - 批量更新不被打断:同一轮里多次改数据只 patch 一次,微任务保证回调紧跟在这批更新后面执行。
3. Vue 2 的降级顺序
Promise.then → MutationObserver → setImmediate → MessageChannel → setTimeout,优先选微任务,只有在不支持微任务的环境(老 IE)才退回宏任务。
# 5.10 http 和 websocket 的差异
| 维度 | HTTP | WebSocket |
|---|---|---|
| 通信方向 | 请求-响应,客户端主动发起(单向拉取) | 握手后全双工,服务端可主动推 |
| 连接 | 短连接;HTTP/1.1 keep-alive 可复用,但仍是"一问一答" | 一次握手后保持长连接 |
| 握手方式 | 普通 HTTP 报文 | 用 HTTP Upgrade: websocket + Sec-WebSocket-Key 完成握手,之后不再用 HTTP 数据帧 |
| 头部开销 | 每个请求都带完整头(Cookie、UA 等),几百字节起 | 握手后是轻量数据帧,头部只有几字节,通信量小 |
| 状态 | 无状态,靠 Cookie/Session/Token 维持身份 | 有状态,连接本身即会话,可绑定用户 |
| 实时性 | 服务端推送要靠轮询(浪费请求)或 SSE(只能服务端单向推) | 真·实时推送,延迟低 |
| 适用场景 | 页面/接口请求、文件传输、幂等 CRUD | IM 聊天、行情推送、协同编辑、我们的 ASR 字幕 / 质检 / 小结实时推送 |
| 需要注意 | 缓存、跨域、状态码语义完善 | 要自己做心跳、断线重连、消息去重与顺序、鉴权(token 放首帧或 URL)、网关/代理对长连接的超时配置 |
一句话总结:HTTP 适合"我要什么",WebSocket 适合"我要你随时告诉我"。
参考:9. 跨域 (opens new window)、图解HTTP 第9章 (opens new window)。
# 6. 主管面
主管面一般围绕这几类展开(回答思路可复用本文第 3 节):
- 之前的业务是什么、做的哪块,需求开发流程怎么走(从需求评审 → 方案 → 开发 → 自测 → 提测 → 上线);
- 线上问题 / 运营问题的处理流程(发现 → 定位 → 应急止损 → 复盘 → 改进);
- 抗压与加班、稳定性、职业规划;
- 面试官会介绍具体业务和团队情况,这时可以顺着问业务方向和技术栈。
综合面试补充:职业规划
答: 1~3年深耕技术,成为团队核心;3~5年向中高级/技术专家发展,能带小团队或独立负责模块。
给面试官的话: 我的规划是短期内扎实做好前端开发,把三维可视化和工程化做深,1~2年内达到中高级水平,能独立负责项目模块。3~5年希望能带小团队或做技术方案设计,往架构方向走。在咱们公司,我了解到有导师带教,我会快速融入,先把手头的事做好,再逐步承担更多责任。
常问问题逐条答案:
1. 技术发展规划,为了达成目标做了什么?
持续学习:看源码、写博客、做开源
项目实践:主动承担复杂模块
复盘总结:每项目结束写总结文档
给面试官的话: 我规划是往中高级前端走,平时会看框架源码、写技术笔记、做 side project。工作中主动接复杂需求,比如性能优化、SDK封装,做完会复盘沉淀。
2. 过往经历中最骄傲的事?
主导/参与某项目从0到1上线
解决重大性能瓶颈,首屏从X秒降到Y秒
封装组件库/SDK,被多项目复用
给面试官的话: 最骄傲的是主导了XX项目的前端架构,从0搭建,封装了公共组件和工具库,上线后支撑了XX业务,首屏性能优化了XX%。
3. 遇到问题怎么处理?有没有引入新东西?
先定位(日志/监控/DevTools)
查文档/搜索/社区
尝试新方案,小范围验证再推广
给面试官的话: 先自己排查,用工具定位根因。如果是技术盲区,查文档和社区,必要时引入新工具或方案,先小范围验证再落地。
4. 工作中感到压力和自豪的事?
压力:紧急上线、线上故障、需求频繁变更
自豪:项目成功上线、性能提升、被认可
给面试官的话: 压力大的是线上紧急问题和密集排期,靠优先级管理和沟通解决。自豪的是自己负责的模块稳定运行,性能优化有明显收益。
5. 遇到困难怎么解决?自己解决还是求助?
先自己查,超过30分钟无进展就求助
求助时带上:问题现象、已尝试方案、怀疑点
事后复盘,沉淀文档
给面试官的话: 先自己排查,卡住超过半小时就带着方案去问,不硬扛。问完会记录解决方案,避免重复踩坑。学到的是:沟通要高效,提问要精准。
6. 上家领导/同事对你的评价?
领导:靠谱、责任心强、技术扎实
同事:好沟通、愿意帮忙、代码规范
给面试官的话: 领导评价我靠谱、有责任心,交给我的事能闭环。同事觉得我好沟通、愿意分享,代码质量稳定。
7. 自我介绍、工作经历、离职原因?
自我介绍:X年前端经验,擅长React/Vue、工程化、性能优化
离职原因:寻求技术成长/业务方向匹配/公司发展
给面试官的话: 我X年前端经验,做过业务开发、组件库、性能优化、SDK。离职是因为想找技术氛围更好、能深入三维可视化方向的团队,和咱们业务方向很匹配。
8. 是否做过管理?如何处理下属摩擦、开发和产品测试意见不一?
带过小团队/带过新人
摩擦:一对一沟通,对齐目标
意见不一:数据说话,拉齐优先级,找共识
给面试官的话: 带过X人小团队/带过新人。遇到开发和产品测试意见不一,我会先听各方诉求,用数据和用户价值判断优先级,实在有分歧就上升给负责人决策,不内耗。
9. 对网上华为黑评怎么看?
理性看待,不跟风
每家公司都有优缺点,看主流
尊重不同声音,但更看重事实
给面试官的话: 网上评价我都理性看,不跟风黑也不盲目吹。任何大公司都有争议,我更关注它实际的技术积累和业务成果。华为在很多领域确实强,这个要客观承认。
10. 如果近期需要和朋友去西安旅游,怎么规划?
定预算和时间
查攻略,定行程(景点、美食、交通)
分工:谁订票、谁订酒店、谁做攻略
留弹性时间
给面试官的话: 我会先和朋友对齐时间和预算,然后分工,我可能负责查路线和美食。用备忘录列好每天的景点和交通,订好酒店门票,留半天机动。西安的话,兵马俑、城墙、回民街这些会安排上。
11. 互联网加班,如何平衡家庭和工作?
提高效率,减少无效加班
重要节点主动投入,平时保证家庭时间
和家人沟通,互相理解
给面试官的话: 我接受互联网的节奏,关键节点会主动投入。平时提高效率,减少无效加班,保证陪伴家人的时间。和家人提前沟通好,互相理解支持。
12. 反问HR:导师带教制度?转内编要求?
导师制:具体怎么带?周期多久?
转正/内编:考核标准是什么?比例多少?
团队:前端团队规模、技术栈、业务方向
给面试官的话: 我想了解下导师带教的具体形式,是全程跟还是阶段性?转内编的考核标准和周期是怎样的?另外想了解下前端团队目前的规模和技术栈方向。
其他注意事项(笔记里已写):
回答不要带口头语("我想一下""嗯""这个")
眼神自然,不盯也不躲
提前进入,不卡点,注意仪容
给面试官的话(综合面收尾): 我的整体规划是先在咱们公司扎实做技术,往三维可视化和中高级前端方向走,能独立扛项目、带小团队。技术上持续学习,业务上快速融入,和团队一起把事做成。