前言
大家好,我是木斯佳。
相信很多人都感受到了,在AI浪潮的席卷之下,前端领域的门槛在变高,纯粹的“增删改查”岗位正在肉眼可见地减少。曾经热闹非凡的面经分享,如今也沉寂了许多。但我们都知道,市场的潮水退去,留下的才是真正在踏实准备、努力沉淀的人。学习的需求,从未消失,只是变得更加务实和深入。
这个专栏的初衷很简单:拒绝过时的、流水线式的PDF引流贴,专注于收集和整理当下最新、最真实的前端面试资料。我会在每一份面经和八股文的基础上,尝试从面试官的角度去拆解问题背后的逻辑,而不仅仅是提供一份静态的背诵答案。无论你是校招还是社招,目标是中大厂还是新兴团队,只要是真实发生、有价值的面试经历,我都会在这个专栏里为你沉淀下来。专栏快速地址
温馨提示:市面上的面经鱼龙混杂,甄别真伪、把握时效,是我们对抗内卷最有效的武器。
面经原文内容
📍面试公司:字节跳动
🕐面试时间:3月30日
💻面试岗位:暑期前端一面
❓面试问题:
- 为什么学 Vue
- 项目中 AI 使用情况
- Promise 常用的 API 有哪些,有什么区别
- Promise 状态含义,怎么流转的
- 链式调用原理,then 不同情况下的返回值
- 讲讲 async await,和 Promise 关系是什么,有什么差别
- 写代码的时候怎么判断要用 async await 还是 Promise
- 三个互不依赖的请求,用 async await 和用 Promise 的区别
- 介绍项目难点
- agent 有哪些范式,差别,应用场景
- 如果有需求用 AI coding 如何落地
- 了解限速工程吗
来源:牛客网 Eastoryy
💡木木有话说(刷前先看)
字节这场一面,是一份异步编程深挖 + AI工程化结合的面经。适合校招/实习同学重点复习Promise底层原理和AI工程化概念。
📝 字节暑期前端一面·深度解析
🎯面试整体画像
| 维度 | 特征 |
|---|---|
| 面试风格 | 异步编程深挖型 + 原理追问型 + AI工程化型 |
| 难度评级 | ⭐⭐⭐⭐(四星,Promise链式调用原理、Agent范式较深) |
| 考察重心 | Promise原理与API、async-await并发、Agent范式、AI coding落地 |
| 特殊之处 | 8道题围绕Promise/async-await,层层递进考察理解深度 |
🔍逐题深度解析
三、Promise 常用的 API 有哪些,有什么区别
| API | 返回值 | 特点 |
|---|---|---|
Promise.resolve(value) | 成功Promise | 将值转为Promise |
Promise.reject(reason) | 失败Promise | 将原因转为失败Promise |
Promise.all(promises) | Promise | 全部成功才成功,一个失败则失败 |
Promise.allSettled(promises) | Promise | 等待所有完成,返回状态数组 |
Promise.race(promises) | Promise | 返回第一个完成的(成功或失败) |
Promise.any(promises) | Promise | 返回第一个成功的(ES2021) |
// 对比示例constp1=Promise.resolve(1)constp2=Promise.reject('error')constp3=Promise.resolve(3)Promise.all([p1,p3]).then(console.log)// [1, 3]Promise.all([p1,p2,p3]).catch(console.log)// 'error'(立即失败)Promise.allSettled([p1,p2,p3]).then(console.log)// [{status:'fulfilled',value:1}, {status:'rejected',reason:'error'}, {status:'fulfilled',value:3}]Promise.race([p1,p2,p3]).then(console.log)// 1(最快完成的是p1)Promise.any([p2,p1,p3]).then(console.log)// 1(第一个成功的是p1)四、Promise 状态含义,怎么流转的
三种状态:
pending:初始状态,未完成fulfilled:操作成功,调用resolverejected:操作失败,调用reject
流转规则:
- 只能从
pending流向fulfilled或rejected - 状态一旦改变,不可逆
constpromise=newPromise((resolve,reject)=>{// pending → fulfilledresolve('success')// 或 pending → rejected// reject('error')// 下面的resolve/reject不会生效(状态已改变)})五、链式调用原理,then不同情况下的返回值
原理:.then()返回一个新的Promise,形成链式调用。
返回值规则:
| then回调返回值 | 新Promise的状态 |
|---|---|
| 普通值 | fulfilled,值为该返回值 |
| Promise对象 | 状态/值跟随该Promise |
| 抛出错误 | rejected,错误为抛出值 |
Promise.resolve(1).then(val=>val+1)// 返回2(普通值)→ fulfilled.then(val=>Promise.resolve(val*2))// 返回Promise → 跟随.then(val=>{thrownewError('fail')})// 抛出错误 → rejected.catch(err=>console.log(err))关键点:.then()如果没有传入回调,会产生透传:
Promise.resolve(1).then()// 没有回调,透传1.then(val=>console.log(val))// 输出1六、async await,和Promise关系是什么,有什么差别
关系:async/await是Promise的语法糖,让异步代码写得更像同步。
差别:
| 维度 | Promise | async/await |
|---|---|---|
| 写法 | 链式调用.then() | 同步风格,await暂停 |
| 错误处理 | .catch() | try/catch |
| 调试 | 链式调用栈较深 | 更直观 |
| 并发 | Promise.all、Promise.race | 需结合Promise API |
// Promise写法functiongetData(){returnfetch('/api/user').then(res=>res.json()).then(user=>fetch(`/api/posts/${user.id}`)).then(res=>res.json()).catch(err=>console.error(err))}// async/await写法asyncfunctiongetData(){try{constres1=awaitfetch('/api/user')constuser=awaitres1.json()constres2=awaitfetch(`/api/posts/${user.id}`)returnawaitres2.json()}catch(err){console.error(err)}}七、写代码的时候怎么判断要用 async await 还是 Promise
回答思路:根据场景选择。
使用async/await的场景:
- 需要顺序执行、依赖前一步结果的异步操作(代码更清晰)
- 需要使用
try/catch统一处理错误 - 循环中有异步操作(
for...of配合await)
使用Promise的场景:
- 并发多个独立请求(
Promise.all、Promise.allSettled) - 需要竞速(
Promise.race) - 需要在
.then链中做复杂变换 - 高阶函数中需要直接返回Promise对象
// 顺序执行 → async/await更清晰asyncfunctionsequential(){consta=awaitfetchA()constb=awaitfetchB(a)returnb}// 并发执行 → Promise.all更合适functionparallel(){returnPromise.all([fetchA(),fetchB(),fetchC()])}八、三个互不依赖的请求,用 async await 和用 Promise 的区别
场景:三个请求没有依赖关系,可以并发执行。
用Promise.all(推荐):
asyncfunctionfetchAllWithPromiseAll(){const[res1,res2,res3]=awaitPromise.all([fetchA(),fetchB(),fetchC()])// 三个请求并发执行,总耗时 = 最慢的那个}用async/await顺序执行(不推荐):
asyncfunctionfetchAllSequential(){constres1=awaitfetchA()constres2=awaitfetchB()// 等待res1完成才执行constres3=awaitfetchC()// 等待res2完成才执行// 总耗时 = a + b + c,比并发慢很多}区别总结:
- 性能:
Promise.all并发,总耗时 = max(T1,T2,T3);顺序执行总耗时 = T1+T2+T3 - 错误处理:
Promise.all一个失败则全部失败;顺序执行中一个失败则后续不执行 - 写法:
Promise.all更简洁
“假并发”陷阱:
// 错误:这样仍然是顺序执行asyncfunctionwrong(){consta=fetchA()// 注意:没加await,但Promise已开始执行constb=fetchB()constc=fetchC()constres1=awaita// 等待a完成constres2=awaitb// b可能早已完成,但这里仍在等待constres3=awaitc}// 实际上fetchA/B/C在声明时就开始执行了,但await的顺序仍会造成等待十、agent 有哪些范式,差别,应用场景
回答思路:Agent范式是构建AI Agent的不同设计模式。
主流范式:
| 范式 | 核心机制 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| ReAct | Thought→Action→Observation循环 | 需要推理+工具调用 | 可解释性强 | 可能陷入循环 |
| Plan-and-Execute | 先规划步骤,再执行 | 复杂任务(旅行规划) | 全局最优 | 规划依赖模型能力 |
| Reflection | 自我反思、迭代改进 | 需要高质量输出(写作、代码) | 输出质量高 | 耗时多 |
| Multi-Agent | 多个Agent协作 | 复杂系统开发 | 分工明确 | 协调复杂 |
# ReAct伪代码whilenottask_complete:thought=llm.think(state)# 思考action=execute(thought)# 行动state.update(action)# 观察应用场景:
- ReAct:客服问答、数据分析
- Plan-and-Execute:旅行规划、项目排期
- Reflection:代码生成、论文写作
- Multi-Agent:游戏AI、软件开发
十一、如果有需求用 AI coding 如何落地
回答思路:从试点、规范、工具链、培训四个阶段。
落地步骤:
- 试点项目:选择低风险、可量化的项目试点(如内部工具、文档生成)
- 建立规范:定义AI coding使用规范(代码审查机制、不允许AI生成核心算法)
- 工具链集成:统一Cursor/Copilot配置、共享Prompt模板、建立AGENTS.md
- 团队培训:培训如何写好Prompt、如何审查AI代码、如何利用AI写测试
- 度量效果:跟踪代码质量、开发效率、AI采纳率
关键点:
- AI生成代码必须本人审查理解
- 敏感信息/密钥不能给AI
- 建立代码片段库,让AI学习项目风格
- 用AI写单元测试、文档、重复性代码
十二、了解限速工程吗
回答思路:限速工程(Rate Limiting Engineering)是控制API调用频率、成本的工程实践。
核心概念:
- Token限流:控制每分钟/每秒请求数,防止过载
- 动态限流:根据服务负载动态调整阈值
- 降级策略:超限时返回默认值、错误或排队
在AI应用中的重要性:
- LLM API成本高,防止被滥用
- 避免服务被打爆
实现方式:
- 令牌桶算法、滑动窗口、漏桶
- 前端:请求去重、防抖、节流
- 后端:中间件限流、Redis计数器
// 前端简单限流:每10秒最多请求1次letlastRequestTime=0functionrateLimitedFetch(url){constnow=Date.now()if(now-lastRequestTime<10000){returnPromise.reject('请求太频繁,请稍后再试')}lastRequestTime=nowreturnfetch(url)}📚知识点速查表
| 知识点 | 核心要点 |
|---|---|
| Promise API | all/allSettled/race/any,区别在于失败处理、返回值 |
| Promise状态 | pending→fulfilled/rejected,单向不可逆 |
| 链式调用 | then返回新Promise,值/新Promise/抛错决定新状态 |
| async/await | Promise语法糖,用try/catch捕获错误 |
| 并发选择 | 互不依赖→Promise.all,有依赖→async/await顺序 |
| Agent范式 | ReAct(思考-行动)、Plan-and-Execute(先规划后执行) |
| AI coding落地 | 试点→规范→工具→培训→度量 |
| 限速工程 | 令牌桶/滑动窗口,控制API频率,防止过载 |
📌 最后一句:
字节这场一面,是一场“异步编程深度+AI工程化广度”的面试。从Promise状态流转、链式调用原理,到async-await并发取舍,再到Agent范式、AI coding落地、限速工程,面试官层层递进,考察的不是你会不会用,而是你知不知道为什么这么用、什么时候该用哪个。能答好这套题,说明你对异步编程的理解已经超越API层面,达到了设计思想层面。