科沃斯前端实习面试:SSE 与事件循环、AI 工具用法
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
- 请做一下自我介绍。
- 介绍你的开源贡献的内容。
- 你的 AI 助手项目用到了什么技术栈?
- SSE 流式响应和 WebSocket 有什么区别?
- 路由懒加载、组件按需加载是怎么实现的?
- 组件库项目的 createVNode + render 工作流程是怎样的?
- 什么是防抖和节流?
- 提交按钮应该选择防抖还是节流?
- 什么是事件循环?
- 什么是微任务和宏任务?
- 当同时出现一些异步数据时,怎么判断哪个执行成功、哪个失败了?
- 你用过哪些 AI 工具?用 AI 工具的一些方法是什么?
- 怎么让 AI 完成长程任务的自闭合?
- 用过哪些给 AI 使用的规则 skills?
《参考解析》
SSE 与 WebSocket:SSE 是「服务器单向推、客户端只收」,跑在普通 HTTP 之上,响应的 Content-Type: text/event-stream,浏览器原生 EventSource 自带断线重连和 Last-Event-ID 续传;它只能传 UTF-8 文本,且受浏览器同域连接数限制(HTTP/1.1 下同域约 6 条),所以生产上一般跑在 HTTP/2 或 HTTP/3 上规避。WebSocket 要先用 HTTP 升级握手(Upgrade: websocket),之后是全双工长连接,能传二进制、延迟更低,代价是心跳、重连、鉴权、代理穿透全得自己实现,很多网关对长连接的闲置超时也需要专门配置。选型看交互模型:像大模型流式输出这种「一问一答、只需服务端持续吐字」的场景 SSE 更省事,失败重连几乎是白送的;而协同编辑、实时对战、需要客户端高频上行(语音、光标位置)的场景必须用 WebSocket。面试高频追问是「为什么不用 WebSocket 做流式输出」——答案就是单向场景下双向能力换来的复杂度不划算,但要注意 SSE 无法中途发送新的用户输入,多轮对话里想打断得另开一条请求。
防抖、节流与提交按钮:防抖是「事件停止触发后等 N 毫秒才执行一次」,中间的触发不断重置计时器,适合搜索联想、窗口 resize 后重算布局这类「只关心最终状态」的场景;节流是「固定时间窗口内最多执行一次」,适合滚动加载、拖拽、鼠标移动这类需要稳定频率反馈的场景。提交按钮的正确做法不是二选一:防抖下用户连点只会推迟提交时机,窗口内依然可能发出两次请求;节流也只是把频率降下来。真正稳的是「点击瞬间立刻置 loading 并禁用按钮,请求结束后再恢复」,再叠加接口层的幂等(前端生成 requestId、后端按它去重),这样才能既不重复下单又不丢用户意图。顺带补一句:移动端点透、回车提交、表单默认提交都要一起拦,否则禁用逻辑会被绕过去。
事件循环与微任务、宏任务:JS 是单线程的,同步代码在调用栈里跑完,然后进入事件循环:每取一个宏任务执行完,就把微任务队列整队清空,之后才可能渲染,再取下一个宏任务。宏任务包括 setTimeout / setInterval 回调、I/O 完成回调、UI 渲染、MessageChannel;微任务包括 Promise.then/catch/finally、queueMicrotask、MutationObserver。所以 setTimeout(fn, 0) 一定排在当前这轮所有 Promise.then 之后;连续追加微任务会饿死渲染(页面卡住但定时器也不执行),这是「微任务里再 then 自己」的经典坑。再深一层:Node 里还分 process.nextTick(比 Promise 微任务还优先)、timers、poll、check 等阶段;await 之后的代码等价于放进微任务。面试官爱追问的手写题大多是「输出顺序」题,解题办法是先给同步代码分段,再在每段后面按「微任务清空 → 下一个宏任务」插队。
路由懒加载与组件按需加载:路由懒加载的本质是代码分割 + 按需请求:import('./views/Home.vue') 这种动态导入会让打包器把该模块单独切成一个 chunk,构建时把 component 换成返回 Promise 的工厂函数(Vue Router 直接支持,React 用 React.lazy 配 Suspense),首次进入该路由才去下载并执行。组件按需加载解决的是「组件库全量引入体积大」:用 unplugin-vue-components / babel-plugin-import 在编译期把 <Button /> 或 import { Button } from 'lib' 改写成指向具体文件的样式与脚本引入,只打包用到的组件。工程上还有三件事要一起做:给 chunk 起可读的名字并配 webpackChunkName 或构建工具的 manualChunks、对下一个可能访问的路由做 prefetch、以及为下载失败准备重试与兜底(弱网下动态 import 失败会直接把页面挂掉,路由级错误边界要有)。踩过的坑是懒加载 + 循环依赖,按需拆包时依赖顺序变了,模块初始化拿到 undefined,这类问题要靠检查 chunk 依赖图和去掉不必要的循环引用来解。
怎么让 AI 完成长程任务的自闭合:先说清「自闭合」指的不是 AI 自己判断做完了,而是每一步都有机器可验证的完成判据。实践上分四件事:一是把大目标拆成有明确产出的子任务,每个子任务都要有可执行的验收方式(跑测试、跑类型检查、跑一段校验收尾脚本),做不到可验证的步骤就不要交给 AI;二是把状态落盘而不是留在上下文里,用任务清单、进度文件、产物文件记录「做到哪一步、下一步是什么」,这样上下文被截断或换一个会话也能续上;三是设置检查点与重试上限,失败两次就换思路或停下来上报,不要无限循环;四是把边界写清楚——哪些目录能动、哪些命令不许跑、什么情况必须问人,规则越少越具体越容易被遵守。这套东西和「给 AI 写规则」是一回事:规则应该描述「我们要达成什么、什么算好」,而不是堆砌禁令,规则一旦多到互相冲突,模型反而会挑最容易的一条执行。追问常落在「怎么防止它假装完成」——答案是让结论由命令输出而不是由模型自述来支撑,看不到真实输出的步骤不算完成。