AI前端开发面试题分享

一面(技术基础)
1. 请简述一下事件循环机制,并说明微任务和宏任务在其中的执行时机。
JavaScript 是单线程的,事件循环是它处理异步任务的核心机制。
浏览器中有调用栈、任务队列和微任务队列。整体流程是:
- 执行全局同步代码(属于一个宏任务)。
- 当这个宏任务执行完后,会清空所有微任务。
- 之后浏览器可能会执行渲染。
- 再从宏任务队列中取出下一个宏任务执行,重复以上过程。
- 宏任务:script(整体代码)、
setTimeout、setInterval、I/O、UI 渲染等。 - 微任务:
Promise.then/catch/finally、MutationObserver、queueMicrotask。
执行时机:
一个宏任务完成后,会立即执行该宏任务产生的所有微任务,然后再进入下一个宏任务。微任务总是插队在下一个宏任务之前执行,所以微任务的优先级比宏任务高。
2. 请手写一个简单的防抖函数,并说明在 AI 对话场景中如何应用。
function debounce(fn, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
AI 对话场景应用:
- 输入联想:用户在输入框连续输入时,不需要每次按键都向后端请求建议,可以等用户停止输入一段时间(如300ms)后再请求联想接口,减少无效请求。
- 流式响应后的自动滚动:AI 流式输出内容时,页面需要自动滚动到底部,但频繁滚动可能抖动,用防抖让渲染平稳后再滚动到底,提升体验。
3. 什么是 Promise,它解决了什么问题?
Promise 是 JavaScript 异步编程的一种解决方案。它代表一个尚未完成但将来会完成的异步操作,有三种状态:pending、fulfilled、rejected,状态一旦改变就不可逆。
主要解决的问题:
- 回调地狱:之前的异步依赖回调嵌套,多层嵌套让代码难以维护。Promise 通过链式
.then()调用实现扁平化。 - 错误处理统一:可以通过
.catch()统一捕获前面所有链路的错误。 - 信任问题:Promise 保证只会被决议一次,回调一定会被异步调用,避免了多重回调、调用过早/过晚等问题。
- 组合能力:提供
Promise.all、Promise.race等静态方法,方便并行控制和竞态处理。
4. 请解释一下什么是流式输出(Streaming),前端如何处理这种数据?
流式输出指服务端持续生成数据,并以分块(chunk)的形式逐步发送给客户端,而不是等全部内容生成完毕一次性返回。这在 AI 大模型对话中非常常见,可以实现打字机式的响应体验。
前端处理方式:
- 使用 Server-Sent Events (SSE):通过
EventSourceAPI 监听服务端推送的文本事件,逐段更新界面。 - 使用 Fetch API 读取流:
fetch(url).then(res => res.body.getReader()),循环读取Uint8Array块,用TextDecoder解码,按行或按标记分割后更新 UI。 - 也可使用 WebSocket,接收分片消息。
关键点:需要处理不完整的数据块,维护缓冲区,拼接完整后再渲染(尤其是对 Markdown 这种结构化文本)。
5. 简单谈谈你对 CSS 盒模型的理解。
CSS 盒模型描述了元素在页面中生成的矩形盒子,由内到外四层:
- 内容 (content):真实内容区域。
- 内边距 (padding):内容与边框之间的空白。
- 边框 (border):包围 padding 和内容的边界。
- 外边距 (margin):与其他元素之间的间距。
两种模式:
- 标准盒模型
box-sizing: content-box:width/height 仅指内容区域,盒子总宽 = width + padding + border。 - 替代盒模型
box-sizing: border-box:width/height 包含 content + padding + border,更符合布局直觉,现代项目中通常全局设置border-box。
理解盒模型是精确布局、避免尺寸计算错误的基础。
6. 解释一下什么是闭包,它在前端开发中有什么作用?
闭包是指函数能够记住并访问其定义时的词法作用域,即使该函数在其他地方被调用。
本质:内部函数保留对外部函数变量的引用,导致外部函数作用域无法被垃圾回收。
在前端开发中的作用:
- 数据私有化:模拟私有变量,模块模式,避免全局污染。
- 函数工厂:创建预配置的函数,例如
bind部分参数。 - 保持状态:在事件处理、定时器、异步回调中保留循环变量或局部状态(解决经典的循环索引问题)。
- 实现高阶函数:防抖、节流、柯里化都依赖闭包保存计时器或累积参数。
注意:滥用闭包可能导致内存泄漏,需适时释放。
二面(深入原理与项目)
1. 在 AI 项目中,你们是如何处理大模型返回的 Markdown 渲染问题的?
我们通常采用以下方案:
- 解析库:使用
marked或remark+rehype将 Markdown 转 HTML,配合highlight.js/prism.js做代码高亮。 - 安全处理:利用
DOMPurify净化输出,防止 XSS。 - 流式容错:大模型流式返回时 Markdown 可能不完整(代码块未闭合等),我们实现状态机缓冲,等检测到完整块级结构(如代码块结束符 ` ````)再进行渲染,或对不完整部分先用纯文本展示。
- 增量渲染:维护 Markdown 源字符串不断追加,触发重新解析,同时用
React.memo或虚拟 DOM 减少重绘;复杂场景引入增量解析器,只解析新部分。 - 自定义组件:将解析后的 AST 映射为自定义 React 组件(如 CodeBlock 带复制按钮、表格响应式、数学公式用
KaTeX),提升交互与视觉。
2. 聊聊 React 的 Fiber 架构,它为什么能提升性能?
Fiber 是 React 16 重构的协调引擎。之前的 Stack Reconciler 采用递归遍历更新,过程不能中断,长时间占用主线程导致卡顿。
Fiber 的核心改进:
- 可中断的异步协调:将渲染任务拆成多个小的 Fiber 节点(工作单元),通过链表结构可随时暂停和恢复。
- 时间切片:利用浏览器空闲时间(
requestIdleCallback或 Scheduler 包)执行工作单元,让出主线程给更高优先级的任务(如用户输入、动画)。 - 优先级调度:不同更新分配不同优先级(如用户交互高于数据获取),高优先级任务可打断低优先级。
- 双缓冲:在内存中构建新的 Fiber 树,完成后一次性提交到 DOM,减少中间状态闪烁。
通过这些机制,Fiber 使 React 能够实现并发渲染,保证复杂应用的响应性和流畅度。
3. 什么是 RAG(检索增强生成),前端在其中扮演什么角色?
RAG(Retrieval-Augmented Generation)是将信息检索与 LLM 结合,先从外部知识库检索相关文档,再将文档作为上下文增强模型的生成,减少幻觉,得到更准确、即时的回答。
前端角色:
- 提供知识入口:上传文档、配置知识库的界面。
- 展示检索证据:在 AI 回答中高亮展示引用的原文片段、来源链接,提升可信度。
- 上下文组装:前端可能将用户问题 + 本地缓存文档片段拼接,再提交给大模型,或与后端约定格式。
- 交互反馈:支持用户对检索结果进行“赞/踩”或引用调整,帮助优化检索。
- 对话管理:结合对话历史,可能前端也需对上下文进行裁剪,确保检索片段和对话都能放进模型上下文窗口。
4. 说说前端工程化中,如何进行性能监控?
主要包括以下方面:
- 核心 Web 指标:使用
web-vitals库或PerformanceObserver采集 LCP、FID/INP、CLS。 - 自定义性能:通过
performance.timing、performance.getEntriesByType('navigation')收集页面加载时间、资源耗时、API 响应时长。 - 错误监控:捕获
window.onerror、unhandledrejection,资源加载错误,上报堆栈和元数据。 - 接口监控:包装
fetch/XMLHttpRequest,记录请求的耗时、状态码、响应大小,统计成功率。 - 上报策略:使用
navigator.sendBeacon或图片打点,在页面卸载时确保数据发送;采样率控制、数据压缩。 - 工程化集成:通过构建插件注入监控代码,自动上传 sourcemap 以解析错误堆栈,配合告警平台(Sentry 等)。
目标是建立可量化的性能基线和实时告警,驱动优化决策。
5. 谈谈你对前端模块化的理解,CommonJS 和 ES Modules 有什么区别?
模块化是将代码拆分为独立、可复用的模块,避免全局变量污染和依赖混乱。
历史方案有 IIFE、CommonJS、AMD、CMD、UMD,最终标准化为 ES Modules。
CommonJS 与 ES Modules 主要区别:
- 语法:CJS 用
require/module.exports;ESM 用import/export。 - 加载时机:CJS 运行时动态加载;ESM 编译时静态分析,构建阶段即可确定依赖关系,利于 tree shaking。
- 输出方式:CJS 输出值的拷贝,基本类型被缓存;ESM 输出值的只读引用,模块内部变化会反映到外部。
- this 指向:CJS 模块顶层
this指向当前模块;ESM 顶层this为undefined。 - 循环依赖:CJS 可能得到不完整副本;ESM 由于是动态引用,能更好地处理循环依赖。
现代项目普遍以 ESM 为标准,借助打包工具兼容。
6. 什么是跨域?你们项目中是如何解决跨域问题的?
跨域是浏览器的同源策略限制:协议、域名、端口任一不同,就不能读取另一源的响应,目的是防止恶意网站窃取数据。
解决方式:
- CORS:服务端设置
Access-Control-Allow-Origin等响应头,支持预检请求,是最正规的方案。 - 代理:开发环境通过
webpack-dev-server或vite的 proxy 将 API 请求转发到同域;生产环境用 Nginx 反向代理,后端 BFF 层转发。 - JSONP:利用
<script>标签不受同源限制,仅支持 GET,已较少用。 - WebSocket:不受同源策略约束,可跨域通信。
- postMessage:用于 iframe 或窗口间的安全跨域通信。
在我们 AI 项目中,调用外部模型 API 主要通过 BFF 代理,既解决跨域又能隐藏密钥,同时可以增加鉴权和流量控制。
7. 解释一下原型链,为什么说 JS 是基于原型的语言?
每个 JS 对象都有一个内部 [[Prototype]](可通过 __proto__ 或 Object.getPrototypeOf 访问),指向它的原型对象。原型对象也有自己的原型,层层向上直到 null,形成原型链。
当访问对象属性时,如果自身没有,就会沿着原型链向上查找。
为什么是基于原型的语言?
JS 中没有传统的类继承,而是通过对象直接继承自另一个对象来共享属性和方法。
构造函数创建实例时,实例的 [[Prototype]] 指向构造函数的 prototype,这就是原型继承。
ES6 的 class 只是语法糖,本质还是基于原型的委托机制。这种动态、可随时修改原型的关系使 JS 非常灵活,称为基于原型的语言。
8. 在 AI 聊天应用中,如何处理长对话的上下文管理?
核心挑战是模型上下文窗口有限(token 限制),需在保持连贯性和控制成本间平衡。
前端策略:
- 裁剪策略:保留最新 N 轮对话,或计算总 token 数,超限时从最早的消息开始移除(保留系统提示词)。
- 摘要压缩:对早期对话生成摘要,替代历史消息,减少 token 消耗。
- 智能保留:标记重要消息(如用户明确要求记住的信息)不被裁剪。
- 用户控制:提供“清空上下文”按钮,允许用户主动重置。
- 本地缓存:前端保留完整历史,仅向后端发送裁剪后的上下文,本地展示可折叠早期消息以优化性能。
- 显示提示:当上下文接近窗口上限时给出提示,避免丢失重要信息。
实际中我们多采用滑动窗口 + 手动清空组合,并考虑在后续版本加入自动摘要。
三面(架构与综合能力)
1. 如果让你设计一个 AI 智能体(Agent)的前端工作台,你会考虑哪些核心模块?
核心模块包括:
- 对话与交互面板:多轮对话,流式渲染,支持用户输入、文件/图片上传,展示代理思考过程(如“推理中”、“调用工具”等状态)。
- 工具与插件管理:可视化配置代理可调用的 API、数据库、代码解释器等,测试工具调用结果。
- 知识库与记忆管理:上传文档、管理向量库,配置长期记忆,查看检索命中记录。
- 任务规划与工作流编排:拖拽式编排多步骤任务,展示代理拆解的计划(DAG 图),可执行、暂停、重试子任务。
- 调试与可观测性:请求/响应日志,token 消耗,工具调用链追踪,错误告警,成本统计。
- 权限与安全:密钥管理,用户权限控制,沙箱环境。
- 仪表盘:性能指标、使用量、成功率等监控面板。
技术考量:采用微前端或插件架构保证可扩展性;通过 SSE 或 WebSocket 保持实时通信;实现流式渲染引擎以处理过程输出。
2. 聊聊你在项目中遇到的最大挑战,你是如何解决的?
(此处以 AI 聊天场景为例)最大挑战是 Markdown 流式渲染中的格式撕裂和性能问题。模型输出逐字到达,频繁重新解析整段 Markdown 并渲染,不仅造成闪烁,还可能因代码块未闭合导致布局错乱。
解决过程:
- 调研发现现有解析库难以处理不完整 Markdown。
- 我们设计了一个增量解析层:基于有限状态机跟踪当前块类型(普通文本、代码块、表格等),等待块结束符才调用完整解析。不完整块先用纯文本安全渲染。
- 使用 React 的虚拟列表和
React.memo减少长列表重绘,仅在尾部增量更新时局部渲染。 - 结合
requestAnimationFrame批量更新,避免频繁 DOM 操作。
最终测试稳定,用户体验显著提升。也让我深刻理解了流式处理与编译原理前端的结合。
3. 你如何看待 AI 对前端开发的影响?你平时如何使用 AI 工具?
影响:
- 大幅提升效率:自动化生成代码、单元测试、样式调整,让开发者更聚焦在架构与交互设计上。
- 降低门槛:非专业开发者也能通过自然语言构建界面。
- 工作重心转移:前端工程师需要更懂 AI 集成、流式处理、大模型限制、安全等;更关注产品思维和对 AI 产出的审查把控。
- 不会完全替代:AI 生成的代码仍需要人类审查、优化性能、保证可维护性,深度业务逻辑需要人工决策。
平时使用:
- 用 GitHub Copilot / ChatGPT 快速补全代码、生成样板,减少重复劳动。
- 解释陌生代码或技术文档,快速学习。
- 分析错误日志,提出可能原因和修复建议。
- 进行技术方案对比,但会自己验证真伪。
- 通过对话快速产出原型设计思路。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)