前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 2026年

    • 2026 年前端面经

# 2026 前端面试题大全:最新面经与框架真题

这份 2026 前端面试题与面经按技术方向持续更新,每道题都提供 30 秒速记、真实示例代码、可交互 DEMO 和面试官追问,适合校招、社招以及中高级前端面试前集中复习。

2026 年的前端面试没有放弃 JavaScript、CSS、浏览器和网络基础,但更强调把原理放进真实项目:排查 React 闭包与渲染性能、解释 Vue 3 响应式、选择 Webpack 或 Vite、划分 Next.js Server Component,以及处理大模型流式输出和审查 AI 生成代码。

# 2026 前端面试题分类

  • 基础核心:JavaScript 与浏览器、CSS 与现代布局、TypeScript、浏览器与网络进阶
  • 主流框架:React 19 与 Next.js、Vue 3、Angular、Svelte 与 Nuxt
  • 工程化:Webpack、Vite、Monorepo 与包工程、测试与质量
  • 渲染与架构:服务端渲染与同构、微前端与模块联邦、性能与安全
  • 跨端开发:Electron、React Native、Flutter、小程序、Taro 与跨端
  • AI 与服务端:AI 前端高频题、AI 应用工程、Node.js 与服务端 JavaScript

如果复习时间有限,可以先按 前端面试题复习路线补基础,再用本页做 2026 高频场景自测;临近面试时再结合 真实公司前端面经模拟追问。

# JavaScript 与浏览器

# 微任务为什么可能让页面“卡死”?

30 秒速记

  • 一个任务结束后,会处理可执行微任务
  • 微任务可以追加微任务,检查点会继续处理
  • 持续追加可能饿死渲染、输入与定时器
  • await Promise.resolve() 仍然只让给微任务
  • 长工作分片,并让出到后续任务或工作线程

微任务把页面拖住,往往是因为队列一直清不空。 每个回调可能只做一点事,却又立即追加下一项,浏览器就迟迟没机会处理输入、定时器和绘制。把循环改成不断等待已成功的期约也可能发生同样问题,因为仍在微任务之间接力。长计算要分批设上限,并适时让出到后续任务;适合独立计算的工作,可以移到工作线程。

面试官追问

追问 1循环里加了 await Promise.resolve(),为什么按钮还是点不动?
参考回答

它只让出当前异步续体,后续又进入微任务。队列持续有新任务时,输入和绘制仍可能等不到机会。

追问 2每处理一百项用定时器续跑,就一定流畅吗?
参考回答

不保证,一百项的耗时可能差异很大。可以按实际耗时预算切片,并保留取消条件。

追问 3用 requestAnimationFrame 处理大量计算合适吗?
参考回答

它在绘制前运行,回调里做太多工作反而会拖慢这一帧。适合短小的视觉更新,重计算仍要拆分或转移。

追问 4怎么确认是微任务饿死,而不是某个单次长函数?
参考回答

录制性能轨迹,看是否连续执行期约或微任务回调,中间长期没有绘制与输入处理。再追踪是谁持续创建下一项。

# React 中的闭包为什么会读到旧状态?

30 秒速记

  • 每次渲染是一份状态快照,回调保留那次闭包
  • 长期定时器与订阅最容易读到旧快照
  • 只依赖前值:setCount(c => c + 1)
  • 需要重新同步的值保留依赖,不随意省略
  • 支持时用 useEffectEvent 分离副作用里的事件逻辑

旧闭包不是状态没更新,而是回调仍在读取创建它时那次渲染的变量。 空依赖的副作用注册一个长期定时器后,后续渲染不会自动替换这个回调。只需要根据前值更新时,函数式更新最直接;需要随参数重新连接时,就保留依赖并重新同步。确实只想在副作用事件触发时读取最新值,可以按版本使用 useEffectEvent,不能借它隐藏真正的依赖。

计数器只需要前值,函数式更新最直接;更新函数在 React 处理状态队列时接收前一个待处理状态,因此 Effect 不必读取 count,也不会每次重建定时器。

import { useEffect, useState } from 'react'

export function Counter() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    const timer = window.setInterval(() => {
      setCount((current) => current + 1)
    }, 1000)
    return () => window.clearInterval(timer)
  }, [])

  return <output>{count}</output>
}
@前端进阶之旅: 代码已经复制到剪贴板

不要机械地把每个值塞进依赖数组。先判断 Effect 是否应该随它重新同步;如果只是回调内部要读最新值,拆分事件逻辑比反复退订、重订更准确。

面试官追问

追问 1计数器一直从零加到一,哪种改法最直接?
参考回答

把 setCount(count + 1) 改成 setCount(c => c + 1)。更新函数读取队列中的前一个状态,不依赖旧回调捕获的数字。

追问 2聊天室房间变了,能用最新值读取来避免重新连接吗?
参考回答

不行,房间标识变化本来就应该重新同步连接。它应是副作用依赖,读取最新值不能替代重新订阅。

追问 3只改变通知主题,不想断开聊天室,怎么拆?
参考回答

把连接依赖保留为房间标识,通知逻辑在副作用事件触发时读最新主题。支持 useEffectEvent 的版本可表达这种区别。

追问 4用 ref 保存最新值,就能删除所有依赖吗?
参考回答

不能,引用更新不触发重新渲染或重新同步。先判断值变化是否应改变外部连接,再决定状态、依赖和引用各自的职责。

# 如何实现可取消、不会串结果的搜索防抖?

30 秒速记

  • 防抖控制何时发请求,序号控制谁能提交结果
  • 输入变化立即清定时器、失效旧序号并尝试取消
  • 每次请求绑定自己的 AbortController
  • 返回数据后再检查身份,统一提交界面
  • 卸载清理;空输入和组合输入单独处理

防抖只减少请求次数,防止串结果还要在提交结果前检查请求是否过期。 输入一变,就清理待触发的定时器、让旧请求序号失效,并尝试取消旧操作;新请求返回后,只有序号仍匹配才能更新界面。取消能减少浪费,但不能作为唯一保障。搜索函数最好只返回数据,由经过检查的出口提交结果,卸载时再清理定时器与请求。

export function createSearch<T>(
  search: (q: string, signal: AbortSignal) => Promise<T>,
  onResult: (value: T) => void,
  onError: (error: unknown) => void,
) {
  let timer: ReturnType<typeof setTimeout> | undefined
  let controller: AbortController | undefined
  let version = 0

  function cancel() {
    version++ // 输入一变就让旧结果失效,不等新请求发出
    if (timer !== undefined) clearTimeout(timer)
    timer = undefined
    controller?.abort()
    controller = undefined
  }

  function run(query: string) {
    cancel()
    const q = query.trim()
    if (!q) return // 调用方同步清空搜索结果
    const currentVersion = version
    const currentController = new AbortController()
    controller = currentController

    timer = setTimeout(async () => {
      timer = undefined
      try {
        const value = await search(q, currentController.signal)
        if (currentVersion === version && !currentController.signal.aborted) {
          onResult(value)
        }
      } catch (error) {
        if (currentVersion === version && !currentController.signal.aborted) {
          onError(error)
        }
      } finally {
        if (controller === currentController) controller = undefined
      }
    }, 300)
  }

  return { run, cancel } // 输入时 run,组件卸载时 cancel
}
@前端进阶之旅: 代码已经复制到剪贴板

空关键词时调用方同步清空结果;组合输入期间暂停提交,结束后再调用 run。搜索函数只返回数据,提交界面统一放在通过序号检查的 onResult 中;abort 用来减少无用工作,版本检查负责阻止旧结果覆盖新输入。调用方提供明确的 onError,避免在定时器的异步回调中抛出未处理拒绝。

面试官追问

追问 1先搜短词再搜长词,旧请求最后回来,怎么挡住?
参考回答

每次输入递增版本号,提交结果前比较本次版本与当前版本。不匹配就丢弃,不能只比较请求是否成功。

追问 2旧请求返回时,新请求还在防抖等待,也能覆盖吗?
参考回答

基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 2026年

    • 2026 年前端面经
      • 2026 前端面试题分类
      • JavaScript 与浏览器
        • 微任务为什么可能让页面“卡死”?
        • React 中的闭包为什么会读到旧状态?
        • 如何实现可取消、不会串结果的搜索防抖?
      • React 19 与 Next.js
      • 性能与安全
      • AI 前端高频题
      • CSS 与现代布局
      • Vue 3
      • React 19 深入题
      • Webpack
      • Vite
      • 服务端渲染与同构
      • Electron
      • React Native
      • Flutter
      • Node.js 与服务端 JavaScript
      • TypeScript
      • AI 应用工程
      • 浏览器与网络进阶
      • Angular、Svelte 与 Nuxt
      • 小程序、Taro 与跨端
      • 微前端与模块联邦
      • Monorepo 与包工程
      • 测试与质量
      • 无障碍与设计系统
      • PWA、Web Components 与新平台能力
      • 图形、实时通信与数据层
      • 高频补充题库
      • 跨站请求伪造CSRF
      • 跨域资源共享 CORS
      • 密码安全
      • 卡顿问题解决
      • 编码优化
      • 如何根据chrome的timing优化
      • Vue性能优化
      • 强缓存命中发生了什么?
      • CORS跨域的原理
      • 创建型-单例模式
      • 结构型-装饰器模式
      • 结构型-适配器模式
      • 结构型-代理模式
      • 行为型-策略模式
      • 中介者模式
      • 享元模式
      • 算法
      • 内存泄露
      • 数组相关
      • 操作DOM
      • Ajax总结
      • 定时器
      • 谈谈你对for in/for of的理解
      • JavaScript 实现对上传图片的压缩?
      • 内存泄露
      • 浏览器API
      • 页面加载执行
      • history路由和hash路由
      • performance相关
      • 组件生命周期
      • React18新增了哪些特性
      • React19新增了哪些特性
      • Vue路由相关
      • Buffer 模块
      • webSocket
      • https
      • webpack编译优化
      • 网络篇 2:图片优化——质量与性能的博弈
      • 渲染篇 1:服务端渲染的探索与实践
      • 不做无用功:基于渲染流程的 CSS 优化建议
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

2026 前端面试题大全:最新面经与框架真题

# 2026 前端面试题大全:最新面经与框架真题

这份 2026 前端面试题与面经按技术方向持续更新,每道题都提供 30 秒速记、真实示例代码、可交互 DEMO 和面试官追问,适合校招、社招以及中高级前端面试前集中复习。

2026 年的前端面试没有放弃 JavaScript、CSS、浏览器和网络基础,但更强调把原理放进真实项目:排查 React 闭包与渲染性能、解释 Vue 3 响应式、选择 Webpack 或 Vite、划分 Next.js Server Component,以及处理大模型流式输出和审查 AI 生成代码。

# 2026 前端面试题分类

  • 基础核心:JavaScript 与浏览器、CSS 与现代布局、TypeScript、浏览器与网络进阶
  • 主流框架:React 19 与 Next.js、Vue 3、Angular、Svelte 与 Nuxt
  • 工程化:Webpack、Vite、Monorepo 与包工程、测试与质量
  • 渲染与架构:服务端渲染与同构、微前端与模块联邦、性能与安全
  • 跨端开发:Electron、React Native、Flutter、小程序、Taro 与跨端
  • AI 与服务端:AI 前端高频题、AI 应用工程、Node.js 与服务端 JavaScript

如果复习时间有限,可以先按 前端面试题复习路线补基础,再用本页做 2026 高频场景自测;临近面试时再结合 真实公司前端面经模拟追问。

# JavaScript 与浏览器

# 微任务为什么可能让页面“卡死”?

30 秒速记

  • 一个任务结束后,会处理可执行微任务
  • 微任务可以追加微任务,检查点会继续处理
  • 持续追加可能饿死渲染、输入与定时器
  • await Promise.resolve() 仍然只让给微任务
  • 长工作分片,并让出到后续任务或工作线程

微任务把页面拖住,往往是因为队列一直清不空。 每个回调可能只做一点事,却又立即追加下一项,浏览器就迟迟没机会处理输入、定时器和绘制。把循环改成不断等待已成功的期约也可能发生同样问题,因为仍在微任务之间接力。长计算要分批设上限,并适时让出到后续任务;适合独立计算的工作,可以移到工作线程。

面试官追问

追问 1循环里加了 await Promise.resolve(),为什么按钮还是点不动?
参考回答

它只让出当前异步续体,后续又进入微任务。队列持续有新任务时,输入和绘制仍可能等不到机会。

追问 2每处理一百项用定时器续跑,就一定流畅吗?
参考回答

不保证,一百项的耗时可能差异很大。可以按实际耗时预算切片,并保留取消条件。

追问 3用 requestAnimationFrame 处理大量计算合适吗?
参考回答

它在绘制前运行,回调里做太多工作反而会拖慢这一帧。适合短小的视觉更新,重计算仍要拆分或转移。

追问 4怎么确认是微任务饿死,而不是某个单次长函数?
参考回答

录制性能轨迹,看是否连续执行期约或微任务回调,中间长期没有绘制与输入处理。再追踪是谁持续创建下一项。

# React 中的闭包为什么会读到旧状态?

30 秒速记

  • 每次渲染是一份状态快照,回调保留那次闭包
  • 长期定时器与订阅最容易读到旧快照
  • 只依赖前值:setCount(c => c + 1)
  • 需要重新同步的值保留依赖,不随意省略
  • 支持时用 useEffectEvent 分离副作用里的事件逻辑

旧闭包不是状态没更新,而是回调仍在读取创建它时那次渲染的变量。 空依赖的副作用注册一个长期定时器后,后续渲染不会自动替换这个回调。只需要根据前值更新时,函数式更新最直接;需要随参数重新连接时,就保留依赖并重新同步。确实只想在副作用事件触发时读取最新值,可以按版本使用 useEffectEvent,不能借它隐藏真正的依赖。

🧪​可交互​动手试试

计数器只需要前值,函数式更新最直接;更新函数在 React 处理状态队列时接收前一个待处理状态,因此 Effect 不必读取 count,也不会每次重建定时器。

import { useEffect, useState } from 'react'

export function Counter() {
  const [count, setCount] = useState(0)

  useEffect(() => {
    const timer = window.setInterval(() => {
      setCount((current) => current + 1)
    }, 1000)
    return () => window.clearInterval(timer)
  }, [])

  return <output>{count}</output>
}
@前端进阶之旅: 代码已经复制到剪贴板

不要机械地把每个值塞进依赖数组。先判断 Effect 是否应该随它重新同步;如果只是回调内部要读最新值,拆分事件逻辑比反复退订、重订更准确。

面试官追问

追问 1计数器一直从零加到一,哪种改法最直接?
参考回答

把 setCount(count + 1) 改成 setCount(c => c + 1)。更新函数读取队列中的前一个状态,不依赖旧回调捕获的数字。

追问 2聊天室房间变了,能用最新值读取来避免重新连接吗?
参考回答

不行,房间标识变化本来就应该重新同步连接。它应是副作用依赖,读取最新值不能替代重新订阅。

追问 3只改变通知主题,不想断开聊天室,怎么拆?
参考回答

把连接依赖保留为房间标识,通知逻辑在副作用事件触发时读最新主题。支持 useEffectEvent 的版本可表达这种区别。

追问 4用 ref 保存最新值,就能删除所有依赖吗?
参考回答

不能,引用更新不触发重新渲染或重新同步。先判断值变化是否应改变外部连接,再决定状态、依赖和引用各自的职责。

# 如何实现可取消、不会串结果的搜索防抖?

30 秒速记

  • 防抖控制何时发请求,序号控制谁能提交结果
  • 输入变化立即清定时器、失效旧序号并尝试取消
  • 每次请求绑定自己的 AbortController
  • 返回数据后再检查身份,统一提交界面
  • 卸载清理;空输入和组合输入单独处理

防抖只减少请求次数,防止串结果还要在提交结果前检查请求是否过期。 输入一变,就清理待触发的定时器、让旧请求序号失效,并尝试取消旧操作;新请求返回后,只有序号仍匹配才能更新界面。取消能减少浪费,但不能作为唯一保障。搜索函数最好只返回数据,由经过检查的出口提交结果,卸载时再清理定时器与请求。

🧪​可交互​动手试试
export function createSearch<T>(
  search: (q: string, signal: AbortSignal) => Promise<T>,
  onResult: (value: T) => void,
  onError: (error: unknown) => void,
) {
  let timer: ReturnType<typeof setTimeout> | undefined
  let controller: AbortController | undefined
  let version = 0

  function cancel() {
    version++ // 输入一变就让旧结果失效,不等新请求发出
    if (timer !== undefined) clearTimeout(timer)
    timer = undefined
    controller?.abort()
    controller = undefined
  }

  function run(query: string) {
    cancel()
    const q = query.trim()
    if (!q) return // 调用方同步清空搜索结果
    const currentVersion = version
    const currentController = new AbortController()
    controller = currentController

    timer = setTimeout(async () => {
      timer = undefined
      try {
        const value = await search(q, currentController.signal)
        if (currentVersion === version && !currentController.signal.aborted) {
          onResult(value)
        }
      } catch (error) {
        if (currentVersion === version && !currentController.signal.aborted) {
          onError(error)
        }
      } finally {
        if (controller === currentController) controller = undefined
      }
    }, 300)
  }

  return { run, cancel } // 输入时 run,组件卸载时 cancel
}
@前端进阶之旅: 代码已经复制到剪贴板

空关键词时调用方同步清空结果;组合输入期间暂停提交,结束后再调用 run。搜索函数只返回数据,提交界面统一放在通过序号检查的 onResult 中;abort 用来减少无用工作,版本检查负责阻止旧结果覆盖新输入。调用方提供明确的 onError,避免在定时器的异步回调中抛出未处理拒绝。

面试官追问

追问 1先搜短词再搜长词,旧请求最后回来,怎么挡住?
参考回答

每次输入递增版本号,提交结果前比较本次版本与当前版本。不匹配就丢弃,不能只比较请求是否成功。

追问 2旧请求返回时,新请求还在防抖等待,也能覆盖吗?
参考回答

能,所以版本号应在输入变化时立即更新,而不是等新请求真正发出。防抖窗口内旧输入也已经失效。

追问 3调用了 abort,还需要序号判断吗?
参考回答

需要,底层可能不支持取消,或数据处理已经继续执行。取消负责减少工作,提交前校验负责结果正确。

追问 4异步定时器回调里直接 throw,调用方能捕获吗?
参考回答

普通调用方捕获不到稍后产生的拒绝。提供明确的错误回调或返回可管理的任务结果,并对主动取消单独处理。

# React 19 与 Next.js

# Hooks 为什么不能写在条件分支里?

30 秒速记

  • 常规状态与副作用 Hook 按调用顺序对应内部记录
  • 条件跳过或提前返回会改变调用序列
  • 条件放入逻辑内部,或拆成单独子组件
  • 自定义 Hook 同样遵守规则
  • use 是特定例外,可条件调用但仍有限制

常规 Hook 必须保持调用顺序稳定,才能把这次渲染对应到正确的状态和副作用。 如果条件分支跳过一个状态调用,后面的内部记录就无法可靠对应。可以始终调用自定义查询钩子,把是否启用作为参数,或者条件渲染一个独立子组件。现代 React 的 use 有专门规则,允许条件调用;这个例外不能推广到 useState、useEffect 等普通钩子。

🧪​可交互​动手试试
function UserPanel({ enabled }: { enabled: boolean }) {
  const [name, setName] = useState('Ada')
  const result = useUserQuery(enabled ? name : null)

  if (!enabled) return null
  return <button onClick={() => setName('Lin')}>{result.data?.name ?? name}</button>
}
@前端进阶之旅: 代码已经复制到剪贴板

这里 useUserQuery 每次都调用,只把“是否请求”作为输入交给它处理。另一种可靠做法是父组件条件渲染 <UserPanel />,让整个子组件挂载或卸载。

fe