作为面试官,我最怕遇到什么样的候选人?

带过大大小小的业务线,也前前后后面试过几百个前端。

说句掏心窝子的话:每次坐在面试官那把椅子上,我最希望的不是找到理由刷掉你,而是找到理由留下你。招到一个靠谱的人,我自己能少掉多少头发------这笔账我算得极其清楚🫡。

但有一些候选人,会在面试的最初 15 分钟就让我产生深深的疲惫感。不是因为技术不行,而是因为一些极其根深蒂固的思维习惯,让我意识到:这个人上了生产,我要花大量精力替他兜底。

以下是几个让我在心里悄悄打叉的真实场景,每一个都附上了能扭转局面的实际做法,继续看👇。


代码是正确的,但没有边界

有一次面试,我给了一道看起来简单的题------写一个带节流的搜索请求函数:

typescript 复制代码
// 候选人的答案,逻辑无误
function useSearch(keyword: string) {
  const [results, setResults] = useState([]);
  
  useEffect(() => {
    const timer = setTimeout(() => {
      fetch(`/api/search?q=${keyword}`)
        .then(res => res.json())
        .then(setResults);
    }, 300);
    
    return () => clearTimeout(timer);
  }, [keyword]);
  
  return results;
}

我没有立刻说不对,而是问了一个后续问题:

用户在弱网下,快速输入了 前端 三个字,第一个字和第三个字的请求都发出去了,但第一个请求在第三个之后回来,会发生什么?

沉默😑。

他意识到了:setResults 会被先回来的旧数据覆盖,用户看到的是一份和当前输入完全不对应的脏结果。但他修复的方案是加一个 loading 状态来遮住这个问题。

这就是我最怕的思维模式------用 UI 掩盖了一个数据层的竞态漏洞 。那个 loading 一旦结束,脏数据依然存在,只是用户暂时看不到而已。

正确的方向是用 AbortController 在发起新请求时物理斩断上一个:

typescript 复制代码
function useSearch(keyword: string) {
  const [results, setResults] = useState([]);

  useEffect(() => {
    if (!keyword.trim()) { setResults([]); return; }
    
    const controller = new AbortController();
    const timer = setTimeout(async () => {
      try {
        const res = await fetch(`/api/search?q=${encodeURIComponent(keyword)}`, {
          signal: controller.signal
        });
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        setResults(await res.json());
      } catch (err) {
        // 主动取消不是错误,不上报
        if (err instanceof Error && err.name !== 'AbortError') {
          reportError(err);
          setResults([]);
        }
      }
    }, 300);

    return () => {
      clearTimeout(timer);
      controller.abort(); // 竞态物理斩断,不是靠时序运气
    };
  }, [keyword]);

  return results;
}

当面试官追问然后会怎样 ,他不是在为难你。他是在测试你有没有在真实的生产环境里被这个场景坑过。能沿着他的追问方向说出需要处理竞态、我会用 AbortController,这个候选人在我心里就已经脱颖而出了。


技术原理背得极溜,但从未推动过任何改变

我遇到过对 React Fiber 的双缓存树解释得极其流畅的候选人,前后端通信机制、渲染管线、优先级调度------讲得如数家珍。

但我问:你在实际项目里,有没有因为理解了这个机制,解决过一个具体的性能问题?

他告诉我,他把这块知识用在了背题上,为了应对面试。

这让我极其难受😖------不是因为背题这件事本身,而是背了这么深的原理,却没有往业务里走一步。

一个原理的价值,不在于你能不能复述它,而在于你有没有用它在某个真实的系统里扭转过局面。

能说我用 React.memouseCallback 之前,先用 React DevTools Profiler 确认了具体的重渲染路径,否则乱用反而会因为浅比较的 overhead 拖慢性能的候选人------这才是让我真正坐直身体的时刻。

所以呢,在准备面试时,每一个原理都给自己配上一个使用场景。哪怕使用场景只是一个自己的玩具项目,也比理论知道但没实践过要扎实得多🤷‍♂️。


给了一个方案,但从未想过这个方案会卡在哪里

我喜欢问一道极其开放的场景题:

让你设计一个多标签页之间的登录态同步方案,用户在一个 Tab 里退出登录,其他所有 Tab 要立刻跳转到登录页,你怎么做?

大多数候选人会给出两个答案:

第一种:用 localStorage 监听 storage 事件。方向正确,能解决基本问题。

第二种:用 BroadcastChannel。更现代,API 更干净。

两个答案都没问题。但我接着问:这个方案在什么情况下会失效?

很少有人能回答出来------

BroadcastChannellocalStoragestorage 事件,在同一个 Tab 内部发出的消息,自己是收不到的 。而在某些浏览器隐私模式下、跨域 iframe 场景、或者 PWA 的 ServiceWorker 独立上下文里,这两个通信机制都会完全失效。

真正在生产里维护过多标签页同步的工程师,一定踩过这个坑。他们的答案会带着一种极其具体的危机感:

主要用 BroadcastChannel,但在降级场景下做了 localStorage + storage event 的兜底。同时在每个 Tab 的 visibilitychange 事件里,重新校验一次后端的登录态,用服务端作为最终的单一事实来源,不完全依赖前端跨 Tab 通信------因为这个信道本身就是不可靠的。

能把自己方案的死穴说出来,再给出兜底方案的候选人,无论级别高低,都能在我这里获得极高的评分。


谈崩溃经历时,说的都是接手了一个烂项目😖

我会在面试末尾,问每个候选人同一个开放性问题:

你职业生涯里,遇到过最难搞的技术问题是什么?

让我极其担忧的回答长这样:

我接手了上家公司的一个远古项目,技术债极多,代码一团乱麻,到处是坑......

这个答案告诉了我他遇到了什么,但完全没有告诉我他做了什么。更重要的是,这种叙述方式隐隐透露出一种思维定势:问题的根源永远在别人那里,我是受害者。

让我坐直身体的回答长这样:

当时我们的首页在 iOS 13 以下的机型上,大约有 1.2% 的用户会触发一个必现的白屏。用 Sentry 看到的是一个 TypeError: undefined is not an object,但调用栈在生产环境被压缩后完全不可读。我花了两天时间,用 BrowserStack 的真机还原了现场,最终定位到是一个第三方 SDK 在旧版 WebKit 下调用了不存在的 ResizeObserver,而我们的 polyfill 加载顺序比 SDK 初始化晚了一步......

排查过程的细节,是工程能力最诚实的证明。 任何人都能说我解决过一个很难的 Bug,但只有真正经历过的人,才能说出具体的工具、具体的路径和具体的死角。


最后说一句

在 2026 年这个 AI 能帮你快速生成八股文答案的年代,面试的淘汰机制已经在悄悄变换维度。

靠刷题和背诵通过的那条路,越来越窄。因为任何 AI 能在 3 秒内搜到的答案,面试官都不会把它当成评分重点。

真正在 2026 年还筛不出来、AI 也无法伪造的东西,只有一种:你在具体的工程现场景里,是否真的遇到过坑、填过坑、在崩溃的系统里解决到天亮🤷‍♂️。

你们觉得呢?

相关推荐
梵得儿SHI3 个月前
Vue 项目实战与性能优化全攻略:从代码、渲染到首屏,一站式解决卡顿慢加载
前端·vue.js·性能优化·vite·前端面试·前端优化·首屏优化
xChive4 个月前
前端请求取消:用 AbortController 从 fetch 到 axios
前端·vue.js·axios·fetch·abortcontroller
叫我一声阿雷吧5 个月前
JS 入门通关手册(45):浏览器渲染原理与重绘重排(性能优化核心,面试必考
javascript·前端面试·前端性能优化·浏览器渲染·浏览器渲染原理,重排重绘·reflow·repaint
叫我一声阿雷吧5 个月前
JS 入门通关手册(43):async/await 原理与异常处理(实战 + 面试,彻底搞懂)
javascript·异常处理·promise·前端面试·async/await·generator·异步编程
叫我一声阿雷吧6 个月前
JS 入门通关手册(38):防抖与节流 原理 + 手写 + 实战场景(面试必考)
javascript·性能优化·前端面试·防抖·节流·js手写题
叫我一声阿雷吧6 个月前
JS 入门通关手册(24):Promise:从回调地狱到异步优雅写法
javascript·前端开发·promise·前端面试·异步编程·js进阶·js异步
叫我一声阿雷吧6 个月前
JS 入门通关手册(23):JS 异步编程:回调函数与异步本质
javascript·es6·前端面试·回调函数·回调地狱·js异步编程·异步本质
叫我一声阿雷吧6 个月前
JS 入门通关手册(21):原型链:JS 继承的底层原理
开发语言·javascript·前端面试·原型链·js继承·js进阶·js面向对象
叫我一声阿雷吧6 个月前
JS 入门通关手册(20):构造函数与原型:JS 面向对象第一课
开发语言·javascript·前端开发·前端面试·构造函数·js进阶·js面向对象