面灵AI→

科大讯飞 AI全栈开发 一面:SSE 流式渲染容错与 InnoDB 索引

轮次
一面
时间
2026-10
来源
牛客网

《面试题目》

  1. 请做一下自我介绍。
  2. 实习期间的项目遇到过哪些困难?是如何解决的?
  3. 另一段实习又遇到什么困难?(开发提效工具建设的项目)
  4. 你是如何向团队成员了解开发流程的痛点的?
  5. SSE 流式输出在前端有哪些实现要点?
  6. 如果采用流式渲染,代码块或其他格式标记迟迟没有闭合、一直阻塞了怎么办?
  7. 针对这些渲染出错、输出中断,有什么容错和降级方案?
  8. 介绍一下 Vue 或 React 的生命周期。
  9. Electron 的 IPC 跨进程通信是在哪个业务场景下使用的?
  10. 技术实现上是什么样的?
  11. Go 的高并发机制是怎样的?
  12. 你对 Java 及其后端开发框架了解多少?
  13. MySQL 的 InnoDB 是如何进行索引的?
  14. TCP 粘包、拆包是怎么回事?或者说 TCP 报文段的结构是什么?
  15. HTTP 和 HTTPS 有什么区别?
  16. 能否接受合肥的工作地点?
  17. 能否接受团队以 Java 和 Python 为主的后端技术栈?
  18. 在项目中,你更倾向于担任负责人还是普通成员?
  19. 如果团队负责人离职,需要你同时承担开发和管理工作、投入较多个人时间,你会愿意接受吗?
  20. 平时有什么兴趣爱好?

《参考解析》

SSE 前端实现要点:协议、增量解析与渲染。 可以用 EventSource,也可以用 fetch 加 ReadableStream 读 text/event-stream。协议上要处理 data 多行拼接、事件以空行分隔,以及跨块被切断的 UTF-8 与 JSON——必须带缓冲,拼完整再解析。渲染上不要每收到一个 token 就 setState 触发整棵树重渲染,用 requestAnimationFrame 或几十毫秒的节流批量刷新;Markdown 要流式解析,已闭合的块先渲染,末尾未闭合的部分单独渲染成「进行中」区域;自动滚底要判断用户是否手动上滑,否则会打断阅读。工程细节还有断线重连与 Last-Event-ID 续传、用注释行发心跳防代理超时、原生 EventSource 不支持 POST(要 fetch 流或 polyfill)、以及服务端必须关掉 Nginx 缓冲。

代码块迟迟不闭合导致阻塞,本质是「解析器在等结束符」,不是网络问题。 处理办法是超时降级:对未闭合的围栏设一个时间阈值,超时就按纯文本或已推断的语言先渲染,等闭合标记到达后再替换成高亮版本;同时限制单次解析的输入长度,避免一个巨大的未闭合块让解析器反复全量重算。更根本的是让解析器把「未闭合」当作合法的中间态,并让高亮按行增量处理。整条链路的容错:网络中断保留已生成内容并支持重试续写、服务端错误转成可读提示而不是白屏、超时给重试或复制已有内容的按钮、渲染异常用 ErrorBoundary 兜住并降级为纯文本。任何降级都要埋点,否则系统长期在降级状态运行而没人发现。

生命周期题要讲「什么时候拿到什么」,而不是背钩子名。 React 函数组件的心智模型是渲染加副作用:useEffect 在提交后执行,依赖数组控制重跑,cleanup 在依赖变化或卸载时执行,空数组等价于 mount 与 unmount;useLayoutEffect 在浏览器绘制前同步执行,用于测量与避免闪烁;React 18 严格模式下开发环境会双调用,用来暴露副作用问题。Vue 3 是在 setup 里注册 onMounted、onUpdated、onUnmounted,本质是组件实例的生命周期钩子,keep-alive 下还有 activated 与 deactivated 两套额外钩子。可以补一句 SSR 下没有真实 DOM,mounted 只在客户端跑。

Electron IPC 分主进程与渲染进程两侧,选型看方向与安全。 渲染进程通过 preload 暴露的 contextBridge 调 ipcRenderer.invoke,主进程用 ipcMain.handle 返回 Promise(请求与响应),单向通知用 send 与 on,主进程主动推给渲染进程用 webContents.send。安全上要开 contextIsolation、关 nodeIntegration,只暴露白名单方法,参数在主进程侧再校验一遍;大文件或高频数据不要走 IPC 序列化,用 MessagePort 或共享内存方案。典型业务场景是本地文件读写、系统托盘与全局快捷键、窗口控制、调用原生能力(串口、打印机),以及把后端长连接放在主进程统一管理再广播给多个窗口。

Go 的高并发是 GMP 加网络轮询器。 goroutine 是用户态轻量协程,初始栈约 2KB、可按需增长;G 由 P(逻辑处理器,数量默认 GOMAXPROCS)调度到 M(操作系统线程)上执行,有本地队列和全局队列,靠 work stealing 平衡负载;阻塞的系统调用会让 P 与 M 解绑(handoff),避免拖住其他 G;网络 IO 走 netpoller(epoll 或 kqueue),就绪后把 G 放回队列,所以几万并发连接只需要少量线程。通信优先 channel(CSP),共享内存用 sync.Mutex 与 atomic。要注意容器里 GOMAXPROCS 与 CPU limit 不匹配、channel 未关闭导致泄漏、以及无节制创建 goroutine 需要 worker pool 或 semaphore 限流。

InnoDB 索引:B+ 树、聚簇索引与回表。 聚簇索引的叶子节点就是数据行,按主键组织,所以主键要短且单调——随机 UUID 会造成页分裂与写放大;二级索引的叶子存主键值,查非索引列要回表,覆盖索引可以避免。B+ 树非叶节点只存键和指针,单页能容纳更多键、树更矮(千万级通常三到四层),叶子之间用双向链表连接,天然支持范围扫描。联合索引遵循最左前缀,范围查询之后的列无法继续用于定位;索引失效常见于列上做函数或运算、隐式类型转换、前导通配 LIKE、以及选择性太低的列。用 explain 看 type、key、rows 和 Extra,Using index 是覆盖,Using filesort 要警惕。

TCP 粘包拆包与 HTTP/HTTPS。 TCP 是字节流,没有消息边界,发送端的 Nagle 合并与接收端的读取时机都会让一条消息被切开或粘在一起,所以应用层必须自己定界:长度前缀(最常用)、分隔符、或固定长度;UDP 有报文边界但会丢包乱序,不能拿来替代。TCP 报文段头部包含源端口与目的端口、序号、确认号、数据偏移、标志位(SYN、ACK、FIN、RST、PSH)、窗口、校验和、紧急指针以及选项(MSS、窗口扩大、SACK、时间戳)。HTTP 与 HTTPS 的差别在 TLS:HTTPS 在 TCP 之上用非对称握手协商出会话密钥,再用对称加密传数据,提供机密性、完整性与身份认证(证书链),代价是握手往返与加解密开销;优化手段是 TLS 1.3 的 1-RTT 与 0-RTT、会话复用、OCSP stapling,以及 HTTP/2 的多路复用。