前两天有位朋友刚面完莉莉丝的前端一面,回来跟我复盘了大半个晚上。我边听边记,越记越觉得这场面试的题目设计挺有代表性的——它不是那种"背完八股文就能过"的套路场,而是把前端八股文里最核心的几个考点,全都换了个角度来问。这篇文章就围绕这场一面,把涉及到的考察方向、每道题背后的真实意图、以及现场应该怎么组织答案,完整拆一遍。适合正在准备2026前端面试的同学,尤其是目标在中大型公司、游戏行业前端岗位的,值得仔细看。废话不多说,直接进入正题。
1. 一面整体节奏:莉莉丝把一场面试拆成了四段
先说这场一面的整体观感。全程大概50分钟,节奏比较紧凑,没有太多寒暄,面试官进门简单确认了身份之后就直接进入正题。整体的时间分配大概是:自我介绍加项目深挖用了15分钟,基础八股轮用了20分钟,手写题用了10分钟,最后反问环节留了5分钟。
这个分配比例其实很值得玩味。很多同学以为一面就是纯背题,但实际上莉莉丝这场一面里,项目深挖的占比一点都不低。面试官在自我介绍阶段就开始在简历上画标记,等你讲完一个项目,他会直接针对某个实现细节往下追。也就是说,一面虽然以基础题为主,但不代表项目可以随便准备。
1.1 自我介绍环节,面试官其实在听什么
这是很多人第一个丢掉分数的环节。大部分候选人的自我介绍是把自己简历上的工作经历、项目名称、用到的技术栈复述一遍,讲完大概一两分钟,面试官点点头,然后自己也不知道这段介绍到底有没有价值。
实际上,自我介绍是整场面试里你唯一拥有完全掌控权的展示机会。莉莉丝这场一面,面试官在听自我介绍时,我判断他主要在做三件事:第一,快速确认你的技术栈和岗位匹配度;第二,从你的表达里提取最近一个项目的业务背景;第三,观察你的逻辑组织能力。
所以正确的自我介绍结构应该是:我是谁,当前做什么方向,最近做的一个核心项目是什么,我在里面的角色是什么,这个项目里最值得说的一件事是什么,最后收一个"我对前端基础有持续整理,尤其关注XXX方向"。不需要长,控制在两分钟以内,但每一句话都要有信息量。切忌把自我介绍变成"我熟练使用React、Vue"这种纯列举,因为面试官接下来一定会从这里面随便挑一个词往下追问。
1.2 项目深挖:一面也会追问到实现细节
很多人对一面有一个刻板印象,觉得只有二面三面才会深挖项目,一面就是走过场。莉莉丝这场一面直接打破了这种预期。
面试官问项目的方式不是"你给我讲讲这个项目",而是先让你讲一遍,然后立刻从你讲的某个点切进去。比如你提到"我用虚拟列表优化了长列表渲染",他大概率会追一句:"你那个虚拟列表的滚动容器是怎么处理动态高度的?"或者说"如果列表项高度不固定,你的方案还能用吗?"
这种追问方式其实暴露了一个核心逻辑:一面虽然考八股,但面试官真正想验证的是你有没有在实际场景里用过这些技术。八股文背得再熟,如果项目里完全没有对应的落地经验,问两句就会露馅。
我在给朋友复盘时给了他一个建议:准备项目深挖时,不要只准备"我做了什么",要为简历上的每一个技术点准备两个层面的答案。第一层是"这个方案是什么、解决了什么问题",第二层是"这个方案在什么条件下会失效、有什么替代方案"。莉莉丝这种一面级别的追问,通常不会超过这个深度。
1.3 基础八股轮:范围广,但频率分布有规律
到了基础题轮次,莉莉丝这场一面的考察范围基本可以划分为四块:JavaScript底层、浏览器与网络、框架原理(以React为主,也会看简历带Vue的情况)、手写代码。
从具体的考察频率来看,JavaScript这块最密集,闭包、事件循环、原型链几乎必考;浏览器与网络里HTTP缓存和跨域是高频;框架题里虚拟DOM和组件通信一定会有一道;最后手写题通常是一道防抖/节流或者深拷贝,配一道Promise输出顺序题。
这个分布其实和绝大多数中大型公司前端一面是一致的。莉莉丝并没有出偏题怪题,但它的问法会带一点游戏行业的特点,比如在问渲染性能时,可能会延伸到"如果页面上有大量动画元素,你的优化思路是什么"。这个问题如果只背"减少回流重绘"这种标准答案,就会显得单薄,后面我会具体展开。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. JavaScript底层题:闭包、事件循环、原型链,每个都不能只背定义
如果把前端八股文按考频排序,JavaScript底层绝对是榜首,这场一面也不例外。但莉莉丝的一面让我印象最深的一点是,它从来不直接问"什么是闭包"这种单句能答完的问题,而是把定义和应用场景、坑点、排查方法串在一起考。
2.1 闭包与内存泄漏:从"什么是闭包"到"哪里会泄漏"
闭包这道题,常见的标准答法是:"函数可以访问它定义时所在的词法作用域,即使外部函数执行完,内部函数仍然持有对外部变量的引用。"
这个答法没有错,但在一面里大概率只能拿到及格分。莉莉丝的面试官在听到这个回答后,立刻追问了一句:"闭包一定会造成内存泄漏吗?"
这里其实是个陷阱。如果你回答"是",说明你对内存泄漏的理解还停留在表面。正确的回答是:闭包本身不会必然导致内存泄漏,内存泄漏发生在"持有闭包引用的那个对象生命周期过长,并且不再需要这个闭包"的场景里。
举个例子,在React函数组件里,useEffect中注册了一个事件监听器,监听函数里引用了组件作用域的state,如果组件卸载时没有移除监听器,这个监听器就会一直持有对state的引用,导致组件占用的内存无法被回收。这本质上就是闭包引起的内存泄漏,但泄漏的根源不是闭包,而是"没有及时解除引用"。
我建议遇到这道题时,答案组织成三段:先给定义,再说一个闭包的实际应用场景(比如防抖函数、柯里化、模块化封装),最后主动提一句"闭包需要注意引用释放,通常在事件监听和定时器场景里容易踩坑"。这样就把一道概念题,变成了"概念+场景+经验"的综合回答,面试官会明显更有兴趣听下去。
2.2 事件循环:宏任务和微任务的输出顺序题
事件循环基本是每一场前端一面都跑不掉的题。莉莉丝这场直接给了一道代码输出题,让你说出多个同步代码、Promise、async/await、setTimeout混合时的打印顺序。
这种题的核心考点有两层:第一层是你知不知道JavaScript是单线程的,事件循环是怎么把宏任务和微任务排队的;第二层是你对async/await语法糖背后的Promise机制理解得到不到位,尤其是await会产生多少个微任务。
先记住最基础的模型:同步代码先执行,执行完后清空微任务队列(Promise.then、MutationObserver、queueMicrotask),然后再取一个宏任务执行(setTimeout、setInterval、I/O事件),宏任务执行完之后又清空微任务队列,如此循环。
容易丢分的地方在await。很多人以为await后面一定要等Promise落定才继续,但其实如果一个函数里写了await一个同步值,V8会把await后面的代码作为微任务放入队列。而如果await后面是一个已经resolved的Promise,V8在展开时可能产生额外的微任务,这在老版本V8里是常见考点。新版V8做了一些优化,但面试时最好按规范语义回答,即"await会中断当前async函数,后面的代码作为微任务延后执行"。
我在这场面经里看到一道非常典型的题目,输出顺序是这样的:
javascript复制console.log('script start');
async function async1() {
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2 end');
}
async1();
setTimeout(() => {
console.log('setTimeout');
}, 0);
new Promise((resolve) => {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise2');
});
console.log('script end');
先不急着看答案,自己心里跑一遍事件循环。最终的输出顺序是:
text复制script start
async2 end
promise1
script end
async1 end
promise2
setTimeout
很多人在"async1 end"和"promise2"的顺序上犯错。关键点在于:async1函数执行到await async2()时,async2函数体是同步执行的,所以"async2 end"立刻打印;然后await让出当前流程,async1后面的代码被包装成微任务放入队列。紧接着new Promise里的执行器同步执行,打印"promise1",resolve后注册了.then回调。同步代码全部跑完后,微任务队列里先有"async1 end",再有"promise2",所以打印顺序是async1 end、promise2,最后才是宏任务setTimeout。
这道题能完整讲清楚,并且你还能主动说出"await后面的代码是作为微任务延后执行,而不是立刻执行",这一问基本就稳了。
2.3 原型链与继承:把class的糖皮剥掉
原型链这道题,莉莉丝的问法是:"class的extends本质是什么?你能不能用ES5的方式实现一个继承?"
这道题直接考察你知不知道class只是语法糖。extends关键字底层是寄生组合式继承。完整回答这个问题的路径是:先从构造函数开始,讲new操作符做了什么(创建一个新对象、把新对象的__proto__指向构造函数的prototype、绑定this、根据返回值决定返回什么);然后讲原型链查找机制,访问属性时沿着__proto__向上找,一直找到Object.prototype,再往上就是null。
接着讲继承方式演进:原型链继承的问题在于子类实例共享父类引用属性;构造函数继承解决了共享问题,但方法无法复用;组合继承既用了原型链又用了构造函数,但会调用两次父类构造函数;寄生组合继承通过Object.create拷贝父类原型切断了多余的调用,这才是class extends的底层实现思路。
我建议现场如果有机会,直接在纸上画一条原型链:实例的__proto__指向构造函数.prototype,构造函数的prototype是一个对象,这个对象的__proto__指向Object.prototype,Object.prototype的__proto__是null。把这条链路画清楚,比背十遍定义都管用。
3. 浏览器与网络:缓存、跨域、渲染三连问
网络与浏览器这部分,莉莉丝这场一面的问题基本集中在HTTP缓存、跨域、浏览器渲染过程这三个方向。这三个方向在八股文里都有标准答案,但面试官真正想听的是你在实际项目里怎么配置、怎么排查。
3.1 HTTP缓存:强缓存与协商缓存的分工逻辑
HTTP缓存这道题,建议按"用户发起一次请求后发生了什么"这条链路来回答,而不是上来就背字段。
先说强缓存。强缓存命中时,浏览器不会发出网络请求,直接读取本地缓存,状态码表现为200 from memory cache或者200 from disk cache。控制强缓存的字段主要是Cache-Control,它有几个值需要分清楚:max-age指定缓存多长时间有效;no-cache表示"不要直接用缓存,必须回源做协商";no-store表示"完全不要缓存";immutable表示"这个资源在max-age内绝对不会变,连协商都不需要"。面试中有很多人把no-cache和no-store混为一谈,这是明显的扣分项。
再说协商缓存。当强缓存失效后,浏览器会带着If-Modified-Since或If-None-Match回源,服务端根据资源是否变化返回304或者200。这里要注意Last-Modified的精度问题——文件在一秒内被修改时可能判断不准确,所以HTTP规范里用ETag(一般是对内容做hash)来兜底。
莉莉丝的面试官在这里加了一个很实际的问题:"你们项目里静态资源的缓存策略一般是怎么配的?"推荐回答是:HTML入口文件用no-cache,保证页面更新后能拿到最新的资源引用;带hash的JS/CSS等静态资源用max-age加immutable,因为它们的内容一变文件名就会变,浏览器可以放心缓存。这个方案在生产环境里非常成熟,这么答会让面试官觉得你不只是在背书,是真的配过。
3.2 跨域:为什么面试官追着CORS问
跨域几乎是必考题,但莉莉丝问的角度是方案选型,而不是单纯让你解释什么是跨域。
跨域的本质是浏览器的同源策略。但要注意,同源策略不是禁止所有跨源请求,而是禁止跨源请求的响应被页面脚本读取。比如script标签、img标签、link标签加载跨源资源是没问题的,这就是JSONP能成立的原理。所以回答跨域题目时,先点明这个本质,面试官会认为你真的理解,而不是死记方案。
标准答案里要覆盖的常用方案:CORS、JSONP、反向代理、postMessage。
CORS是目前的通用解。回答时要能说清楚两个概念:简单请求和非简单请求。简单请求(GET/POST + 有限的Content-Type)会直接发出,响应里带Access-Control-Allow-Origin即可;非简单请求(比如自定义header、PUT、Content-Type为application/json)会先发一个OPTIONS预检请求,服务端确认允许后,浏览器才会发出真正的请求。如果面试官问你"post请求为什么有时候会出现两次",就是在这里挖坑。
JSONP虽然在现代工程里用得少了,但一面问到跨域时大概率会被顺带提起。要能说出JSONP的核心逻辑:动态创建script标签,src指向跨域的接口地址,服务端返回一段"callback(data)"形式的JS代码,浏览器执行这个脚本时就能拿到数据。但要补充JSONP的局限:只支持GET请求,而且依赖服务端配合,安全性比CORS要弱。
反向代理是工程里最常用的方案。开发环境在vite或者webpack里配置proxy,把前端请求转发到后端服务,绕开浏览器的同源策略限制;生产环境一般在nginx上做同域名代理。这里的加分答法是主动说明"代理解决的是开发联调和生产部署时的跨域,而CORS解决的是服务端显式授权跨域访问,两者适用场景不同"。
3.3 浏览器渲染过程与回流重绘
从输入URL到页面展示,这条链路很长:DNS解析、TCP连接、TLS握手、HTTP请求、服务端响应、解析HTML构建DOM树、解析CSS构建CSSOM树、合并成渲染树、布局(Layout)、绘制(Paint)、合成(Composite)。前面网络部分简单提一下就行,重点放在解析渲染这一段。
面试官如果问"为什么操作DOM性能差",你需要回答的关键点是:操作DOM会触发浏览器重新计算布局和绘制,而这个过程的代价比在JS里操作对象高得多。更细一点说,插入或修改样式时,浏览器的Layout阶段需要重新计算元素的位置和尺寸,覆盖的范围越大、层级结构越深,代价越高。
这里需要区分回流(reflow)和重绘(repaint):回流一定会触发重绘,但只改颜色、背景这类不影响布局的属性,只会重绘不会回流。高频触发的回流包括:增删DOM、修改元素宽度高度、修改offsetTop等几何属性、窗口缩放。常见优化手段包括:合并多次DOM操作、使用class切换样式、让动画元素脱离文档流(position:absolute/fixed)、使用transform代替修改left/top,因为transform只触发合成阶段,不触发回流。
莉莉丝这场在提这个问题时,带了一句游戏行业特色:"如果页面上有大量动画元素,你的优化思路是什么?"这时候只答"减少回流重绘"是不够的。更完整的思路是:先识别动画元素的数量和渲染方式,能用CSS动画就不用JS驱动动画;确保动画元素使用transform和opacity,由GPU参与合成;如果动画卡片数量很大,考虑用canvas替代DOM方案;再进一步还可以用IntersectionObserver做视口内按需渲染。这个回答路径能明显体现出你的性能优化思路是分层的,而不是背了一条优化技巧。
4. 框架题:React和Vue的核心底层题
框架题在莉莉丝一面里占了约五分之一的时间,但问的问题不算难,主要集中在虚拟DOM、组件通信、key和diff。这个深度说明一事:一面不要求你把框架源码读得多透,但要求你对框架运行机制有一个正确的理解,并且能把概念跟实际场景对应起来。
4.1 虚拟DOM:一面考虚拟DOM到底想考什么
"虚拟DOM比真实DOM快吗"这个问题,很多人第一次被问都会答"是"。但严格来说,这是一个错误答案,莉莉丝的面试官也在等你纠正它。
正确的认知是:虚拟DOM是一层描述真实DOM结构的JavaScript对象。它的核心价值有两个,第一是跨平台能力——同一套虚拟DOM描述可以被渲染到浏览器、小程序、原生应用等不同宿主环境;第二是编程模型上的提升——开发者不需要手动命令式地操作DOM,只需要声明式地描述UI状态,框架负责计算出最小更新范围。
性能上,虚拟DOM的优势不在于"比直接操作DOM快",而在于它能把多次零散的DOM操作合并成一次批量更新,并且通过diff算法找出最小变更集合。在很多场景下,手动优化过的DOM操作其实可以比虚拟DOM更快,但虚拟DOM带来的开发效率和可维护性是手写DOM优化无法比的。
这个题答到这个层面,面试官给你的评价会明显高于"虚拟DOM是JS对象,操作它比操作真实DOM性能好"这种背诵答案。
4.2 组件通信:状态管理方案与边界
组件通信这道题,题目本身很常见,但莉莉丝会追问到"为什么不用Context直接替代状态管理库"这个层面。
组件通信的标准答案框架是:父传子用props;子传父用回调函数;跨层级或跨路由页面共享状态时,React用Context或Redux/Zustand,Vue用provide/inject或Pinia/Vuex。这个答案没问题,但只说了"是什么",没有说"怎么选"。
面试官真正想考察的是你知道不知道这些方案的边界。以Context为例,Context可以避免层层透传props,但它的一个特性是:Provider的value变化时,所有消费了这个Context的组件都会重新渲染,这种"粗粒度"的更新很多时候不是你想要的。而且Context不建议存放高频变化的数据,否则整个消费子树都会频繁重渲染。Redux或者Zustand这一类状态管理库,本质上是把状态放到组件树之外,并通过订阅机制只通知依赖该状态的组件更新,粒度更细,更适合复杂跨组件状态流。
一面不需要你深入状态管理库的源码,但你需要能说出它们的适用边界:简单的项目里,props + Context足够;业务复杂、跨组件共享状态多,才值得引入状态管理库。这个"知道取舍"的能力,比背一堆API重要得多。
另外,React里还有个高频衍生题:setState是同步还是异步。标准回答是:在React 18的自动批处理机制下,所有在React事件处理函数、生命周期、hooks里的setState都会被批处理为异步更新,但你可以在非React事件环境(比如setTimeout、原生事件监听器)里验证state是否同步更新,React 18之后即使是这些场景默认也会被批处理。Vue那边对应的问题是nextTick,它的原理是把DOM更新推迟到下一个tick,让你在修改数据后能拿到更新后的DOM。这些题都属于"框架使用经验"的直接映射,准备时最好结合自己项目里真实踩过的坑来讲。
4.3 key的作用与diff算法
关于key,一个最经典的反例就是"为什么不能用数组index作为key"。很多人知道不能用index,但说不清楚原因。
key的作用是在同一层级的子节点中标识节点的身份。diff算法做同级比较时,如果两个节点的key和tag都相同,就认为这个节点可以复用,然后递归比较它的属性;如果key不同,就认为这是两个不同的节点,直接新建和销毁,不做深入的子节点比较。
使用index作为key的问题,出现在数组的顺序发生变化时。比如你有一个列表,渲染时用index作为key,当你在头部插入一条数据,React或Vue会发现"key=0的节点还是那个DOM节点,但数据内容已经不是原来的那条了",于是它会复用这个DOM节点去展示新数据,就可能导致该节点内部状态错乱,比如输入框里保留着旧值、checkbox的选中状态对不上号。
如果节点内容完全静态、不依赖状态、数组也不会乱序,用index做key不是不能用,但一旦涉及顺序变化或组件内部状态,就会踩坑。规范做法是使用业务数据里稳定唯一的id作为key。
diff算法这里,能答出三个核心策略就够了:第一,只做同层级比较,不跨层移动;第二,节点类型不同就直接销毁重建,不去做深层diff;第三,通过key标识节点,在同级比较时尽量复用。这三个策略把原始diff算法的O(n^3)复杂度降到了O(n)。一面层面,能清楚说出这三个策略,已经足够证明你读过diff相关的源码。
5. 手写题与代码输出题:这里最容易暴露真实水平
手写题是最能检验"背了八股文但不一定会用"的环节。莉莉丝这场一面的手写题不算难,就是防抖和深拷贝,外加一道Promise输出顺序题。但写对和写得好,差距非常大。
5.1 手写防抖:要能说出应用场景才算会
防抖的代码很多人能默写出来,但一面面试官通常会追加问一句:"你项目里什么时候用到了防抖?"如果回答不上来,手写题就算白写了。
防抖的核心逻辑是:事件触发后不立即执行,而是等待一段时间,如果等待期间再次触发,就重新计时,只有最后一次触发后的等待时间结束时才执行。代码实现:
javascript复制function debounce(fn, delay = 300) {
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
注意两个细节:第一,回调函数里的this必须通过apply绑定到实际调用者,否则在事件绑定场景下this会丢失;第二,参数通过rest参数透传,保证事件对象等参数能正常传给业务函数。
更进阶一点,面试官可能会问"需求是第一次点击立即执行,后续点击才防抖,怎么写"。这就是leading版本的防抖,实现时加一个是否可以执行的判断:
javascript复制function debounceImmediate(fn, delay = 300, immediate = true) {
let timer = null;
return function (...args) {
const callNow = immediate && !timer;
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
}, delay);
if (callNow) fn.apply(this, args);
};
}
这里的关键是理解"timer是否为null"在这个版本里代表"当前是否在等待期内"。第一触发时timer为null,callNow为true,立即执行,然后设置timer;等待期内再次触发,timer存在,callNow为false,只做重新计时;等待期结束后timer被置空,下一次触发又能立即执行。
接着用场景问题去巩固这两个版本:搜索框输入联想、按钮重复提交,用防抖;滚动加载、mousemove计算坐标,用节流。防抖和节流的区别就是"防抖是把多次触发合并成最后一次,节流是控制一个时间窗口内最多执行一次"。
5.2 深拷贝:边界条件比主流程更值钱
深拷贝这道题,第一反应用JSON.parse(JSON.stringify())是最常见的做法,但面试官一定会追问"这个方案有什么问题"。
JSON序列化方案的问题至少有这几个:函数、undefined、Symbol会被直接丢弃;Date对象会被转成字符串;RegExp会被转成空对象;对象里有循环引用时直接抛错;Map和Set无法被正确还原。所以真正能展示功力的深拷贝,至少要处理这些边界条件。
一个能过一面关卡的递归版本,核心流程是:判断当前值类型,如果非对象直接返回;判断循环引用(可以用WeakMap记录已经拷贝过的对象,一旦遇到直接返回之前拷贝的引用);根据Object.prototype.toString判断具体类型,Date和RegExp单独处理;然后初始化目标容器,递归拷贝所有key。这里如果能把symbol key和不可枚举属性也考虑到,就是超出预期的加分表现。
手写时要注意递归死循环的坑。如果对象里有循环引用,比如a.self = a,不做WeakMap记录就会无限递归。这是这道题里最常见的翻车点。
5.3 Promise输出顺序题:async/await微任务数量是重灾区
前面事件循环部分已经讲了一道输出题,这里要单独提醒的点是:同一道题里,如果你只是"大概知道输出顺序"但不能解释清楚为什么这个微任务排在那个微任务前面,面试官会认定你是在背题,而不是理解。
建议手写这道输出题时,在纸上分列三行:同步任务、微任务队列、宏任务队列。每遇到一行代码,先判断它是哪类任务,把它放进对应的列,然后按"同步执行完 -> 清空微任务 -> 取宏任务 -> 再清空微任务"的规则模拟执行。整个过程不要跳步,哪怕输出了一个"console.log"也要在纸上标记出来。这个复盘习惯我在后来陪朋友模拟了好几次,非常有效。
补充一个很多人忽略的细节:Promise构造函数里的代码是同步执行的,只有.then、.catch、.finally里的回调才是微任务。所以new Promise(() => { console.log('in promise'); })里的console.log会立刻输出,而不是进入微任务队列。这个点经常被混在一起,面试时尽量主动说清楚。
6. 行为问题与反问:技术一面也会看的软素质
莉莉丝这场一面在最后阶段留了五分钟反问。这五分钟虽然看起来不影响技术评分,但面试官其实在观察你的沟通方式和对这份工作的态度。这一轮表现得好,有时能弥补前面某些题答得不够完整的印象。
6.1 项目难点怎么讲才有说服力
行为面试题里最常见的是"讲一个你最有成就感的项目"或者"你遇到过的最大技术难点是什么"。莉莉丝的一面虽然没有专门问行为题,但在项目深挖中其实已经隐含了这个考察方向。
讲项目难点时最忌讳空对空地说"这个项目很复杂、时间很紧、最后我解决了"。要按"背景-任务-行动-结果"的框架来组织:先说这个项目在什么业务背景下、要解决什么问题;再说你在这个项目里具体负责哪部分、遇到了一个什么样的具体困难;然后说你采取了哪些行动,注意要包含方案对比和选型理由;最后说结果,最好有量化数据支撑,比如页面渲染耗时从2秒降到500毫秒,首屏加载速度提升40%。
量化数据不是硬编出来的,如果你没有真实数据,可以把"性能提升"换成"稳定性提升,上线后没有出现崩溃和报错"这种同样可验证的说法。关键是让人感觉到你真的解决过问题,而不是在背一个模板。
6.2 反问环节问什么能加分
很多人在反问环节喜欢问:"咱们团队加班多吗""这个岗位的年终奖大概多少"这类问题。这类问题不一定减分,但对于技术一面来说太可惜了——你本来可以借这个环节收集情报,顺便展示你对技术团队的思考。
我建议从这个方向问:一是问团队当前的技术重点,比如"咱们前端团队当前最大的技术挑战是什么,是性能优化、工程化建设,还是业务交付压力比较大";二是问合作流程,比如"代码评审是怎么做的,发布流程是自动化的还是部分自动化";三是问新人成长,比如"如果入职后希望我快速创造价值,您觉得我最需要补足哪个方向的能力"。
这三个方向的问题不会踩雷,而且面试官通常都会给出有效信息。你会从中得到两个好处:当面对比多个offer时知道哪边的技术土壤更适合自己;更重要的是,你表现出了一个"愿意干活、想清楚怎么干活"的候选人形象,这不是靠背八股文能装出来的,但可以在反问环节真实体现出来。
面经这个东西,很多人把它当成题库来刷,刷完一套记一套,觉得记住了题目就能过关。但看完莉莉丝这场一面,我相信你已经感觉到了:前端面试早就不是"背答案"就能应付的考试了。每一个八股题背后都挂着一个真实场景,面试官轻轻一追问,你到底有没有做过、有没有想过,就全暴露了。所以在准备2026年前端面试时,我强烈建议你换个思路——遇到一道题,先不看答案,自己把相关的底层机制、应用场景、常见坑点都写下来,再回到项目里找对应的例子。这样准备一轮,比你刷十套面经都有效。后面我还会拆解其他公司的一面和二面,欢迎持续关注,也祝正在准备面试的各位能拿到满意的offer。
