小米 AI 前端实习一面:流式渲染背压与团队 AI 协作
- 轮次
- 一面
- 结果
- 通过
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
- 自我介绍。
- 共享屏幕手撕两道算法题:一道反转类题目,一道非 Hot 题。
- 防抖和节流分别用在什么场景?
- HTTP 协议底层用的是什么连接?
- WebSocket 是什么东西?特点是什么?
- SSE 是什么?有什么场景下能用到?
- 平时代码管理器用的什么?
- git merge 和 git rebase 的区别?它们各自的特点?
- 提交完发现有问题,要从 master 上撤回来,用什么?
- 在界面上怎么去调试性能问题?比如今天页面突然很卡,你怎么排查?
- 自上而下和调用树之间的区别?了解过这两个吗?它排查下来是怎么用的?
- 平时用 React 多吗?Vue 的基本原理是什么?它是怎么做渲染的?
- 你有完整部署过一个项目吗?
- 反向代理和正向代理的区别?
- 做过流式输出对话的那些界面吗?
- 项目是干嘛用的?
- React 架构是干什么的?那个 loop 又是什么?跟 React 有什么关系?
- 场景题:大模型在 100 毫秒内吐了 1000 次,吐太快会导致前端界面卡顿,这种情况怎么优化?用什么方式?什么数据结构?(面试官补充的比喻:上游供给端是个大坝,供水过多,下游界面的消费能力有限)
- Vue 框架什么时候会触发复用 DOM 节点?
- 场景题:假设有个上百人的团队,每个人每天都用 AI 写代码,有些情况下需要人为提供经验。有些对话会发现 AI 改错了,我们希望这类经验能被所有人复用——发现问题、补充进去、所有人都能得知。这套团队知识体系建设如果是你来做,会从哪些方向或者架构理念切入?
- 如何保证在 AI 写代码的情况下,线上不会出事故?如何保证质量?
- 如果管了 100 个团队,你一个一个去 review 吗?
- 了解端到端测试吗?无头浏览器听过没?
- 反问环节:公司的业务?全栈趋势?
《参考解析》
流式渲染的背压(第 18 题):这是整套题里最有含量的一道。问题本质是生产速度远大于渲染速度,直接每来一个 token 就 setState,会让 React 在 100ms 内触发上千次渲染,主线程被 reconciliation 占满,页面自然卡。解法分三层:
- 不每次渲染,做批量合并。最简单的是定时刷新——用
requestAnimationFrame或固定间隔(16ms / 50ms)把这一段时间内到达的 token 一起提交,把渲染频率从”每个 token 一次”压到”每帧一次”。也可以用微任务合并(在一个 microtask 里累积、下一个 microtask 统一 flush)。 - 削峰的数据结构:用一个队列(数组)当缓冲区,token 到达就入队,渲染循环按帧从队头取出并拼接;队列长度就是水位,可以用来做反馈。大坝那个比喻对应的正是”缓冲区 + 按消费能力消费”,超出水位时就该让消费端表态(比如暂停上游读取)。
- 真正的背压:如果上游是 SSE / fetch stream,可以用
ReadableStream的pull语义——消费端不 ready 就不拉下一块;WebSocket 侧则可以在水位过高时发一条”暂停”信号给服务端,让服务端降低发送速率。此外还有渲染侧的优化:把已定稿的段落拆成不随流的静态组件并memo,只让最后一段参与高频更新;用useDeferredValue或 transition 把非紧急更新降级;文本用textarea+value直接赋值这类不触发 diff 的方式。答题时把”合并渲染 → 缓冲队列 → 反馈上游”这三步说出来,比只答”用防抖”完整得多。
WebSocket 与 SSE:WebSocket 是全双工、基于 TCP 的独立协议(一次 HTTP 升级握手后长连),适合双向实时交互,比如协同编辑、聊天、游戏状态同步;SSE 是单向的服务端推送(基于普通 HTTP 的 text/event-stream),浏览器原生 EventSource 支持自动重连和事件 id,适合”服务端持续下发、客户端只听”的场景,比如 AI 对话流式输出、进度通知、行情推送。选型看方向性:只需要服务端推就用 SSE(实现简单、能过大多数代理),需要双向就上 WebSocket。
git merge 与 rebase:merge 保留真实历史并生成一个合并提交,历史呈分叉结构,适合主干合并分支;rebase 把当前分支的提交”搬”到目标分支最新提交之后,历史是一条直线,可读性好,但会重写提交哈希——所以绝不要对已经推送并被他人使用的公共分支做 rebase。撤回方面,还没推送时用 git reset(--soft 保留改动、--hard 丢弃)或 git commit --amend;已经推送则用 git revert 生成一个反向提交,不要在共享分支上 reset 后强推。
性能卡顿怎么查:先用 Performance 面板录一段卡顿期间的操作,看主线程上是谁在占用——长任务(Long Task)会直接标红。常见元凶是频繁的布局抖动(反复读写 offsetHeight 触发强制重排)、过大的列表没有虚拟化、高频事件(scroll / resize / mousemove)没做节流、以及大量 DOM 节点同时更新。调用树(Call Tree)适合看”哪个函数累计耗时最多”,自下而上(Bottom-Up)适合看”哪个函数被调用了最多次 / 自身耗时最高”,两者配合能快速定位到热点函数而不是只看表层。
团队级 AI 知识体系(第 20 题):可以做成一个闭环:沉淀——把”AI 改错了并且被人工纠正”的对话自动抽取成结构化条目(场景、错误模式、正确做法、涉及文件),而不是存原始聊天记录;分发——按模块 / 技术栈打标签,落到代码仓库的约定文件(如目录级规则)、评审 checklist 和 AI 助手的系统提示里,让下一次生成时就能读到;生效验证——同样的场景重跑一遍,看是否还会犯;治理——有 owner、有去重与过期机制,避免规则越堆越多把模型带偏。核心认知是:给 AI 的规则要少而准,一条经验要能说清”什么情况适用、为什么”,否则所有模型会长成同一个样子。
如何保证 AI 写的代码不出事故(第 21 题):不能靠”让人逐个 review”。有效的组合是:把 correctness 前移到可机器验证的环节——类型检查、lint、单测、构建门禁必须全绿才能合;关键路径加端到端探针和发布后的 canary;对数据库迁移、支付、权限这类高风险改动做改动面识别,命中了就必须人审;再配合灰度发布与快速回滚能力。另外要接受”AI 会犯错是常态”,所以设计的重点不是”让它不犯错”,而是”错了能很快被发现并回滚”——可观测性、回滚演练、变更审计比 review 更兜底。