面灵AI→

小红书前端开发岗面经合集:组件库、构建工具与页面体验优化

轮次
多轮面试合集
时间
2026-10
来源
牛客网

《面试题目》

面经 01 · 小红书 前端开发岗(2025-12-07)

  1. 团队组件库的应用场景有哪些?哪些业务会使用这些组件?
  2. 对比一下团队组件库与其他组件库的差异或优势?
  3. 在组件库研发过程中遇到的最难的问题是什么?
  4. 从接到问题到上线收尾的耗时及各阶段时间分配是怎样的?
  5. 基于现有的前端开发经验,如果再遇到类似的问题,会在哪些环节节点提升效率、更有章法?
  6. 做 B 端与 C 端开发在感受上的最大差异是什么?
  7. 实习经历里最满意的点和没那么满意的点分别是什么?
  8. 为何选择移动互联网及前端开发方向?
  9. 前端技术栈方向上独立学习进步最大的时间段是什么时候?
  10. 规划工作 1-3 年内希望成长为怎样的人?
  11. 秋招时为何投递小红书?

面经 02 · 小红书 前端开发岗(2025-12-07)

  1. 说说项目里缓存的设计。
  2. 算法:n 表示括号对数,设计一个函数生成所有括号的可能性。
  3. 算法:给一个链表的头节点 head,判断链表是否有环。

面经 03 · 小红书 前端开发岗(2025-11-29)

  1. webpack 和 vite 的区别是什么?什么场景用哪个?
  2. 打包工具怎么做代码体积、按需引入的优化?代码里怎么写?
  3. React.lazy 底层是怎么实现的?它配合 Suspense 使用的原理是什么?
  4. 动态导入的话,编译后的代码是什么样的?
  5. script 动态加载时,defer 和 async 都是干什么的?
  6. preload、prefetch 属性有了解吗?
  7. 性能优化指标有哪些?
  8. useMemo、useCallback、React.memo 的区别与联系是什么?
  9. 父子组件什么场景会用到这些性能优化方式?
  10. useState 每次执行时,怎么记录之前的状态的?
  11. fiber 的作用是什么?怎么实现空闲时候调度的?
  12. 怎么实现多页面通信?
  13. MessageChannel 和 BroadcastChannel 有什么区别?

面经 04 · 小红书 前端开发岗(2025-11-29)

  1. H5 页面的滚动怎么处理,让它更丝滑?
  2. 流式输出怎么实现?
  3. WebSocket 有什么特点?
  4. 怎么定义聊天体验?
  5. 从用户视角出发,有哪些体验优化点?
  6. bridge 用到哪些能力?
  7. 移动端怎么根据分辨率适配?
  8. 现在的登录方案是用 JWT 做的,还了解其他方案吗?
  9. 怎么支持双端开发?
  10. 有做性能优化吗?性能优化哪些指标,怎么获取?
  11. 优化 LCP 怎么做?
  12. 缓存如何控制?有哪些相关 API?
  13. 手撕:实现一个发布订阅者模式。

面经 05 · 小红书 前端开发岗(2025-11-29)

  1. Vue2 和 Vue3 的区别是什么?
  2. 虚拟 DOM 的作用是什么?
  3. 手撕:找到字符串中所有字母异位词。

面经 06 · 小红书 前端开发岗(2025-11-29)

  1. 介绍下项目和实习亮点。
  2. 介绍下项目和实习最大的难点——复杂在哪里,解决思路是什么?
  3. 介绍下最大的创新点——为什么要做,有什么提升?
  4. 有没有主动推进过一些工作?结果如何?
  5. HTTP 状态码 304,服务端对应的 headers 是什么?
  6. JS 内存泄漏,如何快速定位到哪一行代码?

面经 07 · 小红书 前端开发岗(2025-11-29)

  1. React 有哪些组件传值方式?
  2. 为什么实习项目用了 zustand 做状态管理?
  3. zustand 等状态管理和 useContext 有什么区别(性能上、使用上)?
  4. coding:手写一个简易的 Store 状态管理类,实现 getStore、create、dispatch 三个方法。
  5. XSS、CSRF 有没有了解?怎么防范?
  6. 前端有哪些缓存?
  7. 跨域的原因和解决方案是什么?
  8. 你对前端领域哪一块感兴趣?例如跨端、性能优化、前端工程化、大前端、前端+AI。
  9. 你做过哪些 AI+前端的尝试?你认为大模型对前端开发有什么帮助?
  10. 前端性能优化有哪些指标?
  11. 如何做的懒加载?
  12. 还有什么你的亮点、我没有覆盖到吗?
  13. coding:写一个上楼梯方案数(dp)。

面经 08 · 小红书 前端开发岗(2025-11-24)

  1. 上来一道动态规划代码题(力扣链接),写完解释。
  2. TCP 三次握手四次挥手。
  3. TCP 和 UDP 的区别是什么?
  4. TCP 的「可靠」机制是什么(拥塞控制、流量控制、慢启动、快速重传)?
  5. 进程和线程的区别是什么?
  6. 介绍一下 scss,它在项目中起到什么作用?
  7. 了解 less 吗?
  8. 打包工具有了解吗?
  9. webpack 比 vite 的优势是什么?
  10. webpack 和 vite 谁启动快?
  11. 输入 URL 到整个页面渲染出来的过程是什么?
  12. 渲染页面详细讲一下。
  13. 在前端中遇到哪些难点?
  14. React 和 Vue 的区别是什么?
  15. 怎么排查 bug?
  16. 关于其中一个项目是怎么去设计的?
  17. 再拓展一下其中的一个功能。
  18. 实习中遇到问题怎么办?

面经 09 · 小红书 前端开发岗(2025-11-19)

  1. 介绍其中一个项目的流程。
  2. 该项目中某一环的逻辑是什么?
  3. TCP 三次握手四次挥手。
  4. HTTP 缓存。
  5. 懒加载与预加载。
  6. 手撕:判断链表中是否有环。
  7. 手撕一道算法题(面试官提示用回溯做)。

面经 10 · 小红书 前端开发岗(2025-11-07)

  1. 对毕业之后第一份工作有哪些期待?
  2. 为什么暑期没转正?还在进行中的流程有哪些?
  3. 刚才说对小红书意向很高,除了 base 地,还有哪些吸引你的点?
  4. 既然有过算法、AI 的经历,为什么现在选择前端开发?
  5. 为什么出国读书?在国外的学习有什么收获和成长?对比在国内的本科经历,有什么不一样?
  6. 介绍一下实习遇到的最大挑战,用 STAR 法则讲。

《参考解析》

组件库与工程化:先讲边界,再讲手段

组件库的问题几乎都会从「通用性和扩展性怎么考虑」切入。稳妥的答法是先定边界:一个组件库要先划分基础组件(按钮、输入框,只关心视觉与交互)、业务组件(带接口请求与业务规则)、以及布局与工具层,不同层的通用性要求完全不同——基础组件要尽量无业务假设、通过 props 与插槽暴露变化点,业务组件则允许收敛在具体场景里。扩展性靠三件事:受控与非受控都支持(v-model / value + onChange 两种用法都留口子)、用插槽或 render props 替代硬编码结构、以及把样式与主题抽成设计令牌(CSS 变量 + token),这样换肤和换品牌不用改组件源码。做按需引入常用的手段是「组件目录按入口拆分 + 构建产物保留 ESM」让打包器的 tree-shaking 生效,或者用 unplugin 类的自动导入插件按需注入样式;如果组件本身是整包注册的,那就只能在构建层做代码分割,效果有限。

构建工具那一串问题要连成一条线答。webpack 是「先打包再起服务」,启动和热更新都要把依赖图走一遍,所以大项目冷启动慢;vite 开发态用原生 ESM 按需请求、依赖用 esbuild 预构建,所以启动快、HMR 只失效单个模块,生产构建默认还是 rollup。选型上的分界是:历史包袱重、需要复杂 loader/plugin 生态和特殊构建能力(如 Module Federation)的用 webpack;新项目、以现代浏览器为目标的基本都选 vite。要注意追问常常落在「vite 生产环境为什么还是打包」——因为浏览器对成千上万个模块的请求会有瀑布,打包仍然是最优解,vite 的优势主要在开发态与构建速度。tree-shaking 的原理是:ESM 的导入导出是静态可分析的,打包器在编译期就能标出未使用的导出并摇掉,所以它要求用 ESM 语法、避免 require 和副作用不可判定的写法(sideEffects 字段就是用来告诉打包器哪些文件有副作用、不能删)。

React 运行时与性能:memo、fiber 与代码分割

React.memo 是给组件做 props 浅比较、相等就跳过重渲染;useMemo 缓存的是计算结果,useCallback 缓存的是函数引用,后两者常常是为了让传给 memo 子组件的 props 保持稳定引用。三者的关系要点明:memo 是「跳过渲染」,useMemo/useCallback 是「稳定依赖」,如果父组件里没有 memo 子组件,光加 useMemo 基本没有收益,反而多了依赖数组和缓存开销。父子组件真正需要这套优化的场景是:子组件渲染成本高(大列表、图表、富文本)、父组件因无关 state 频繁更新、或者子组件被用在依赖引用相等的 effect 里。fiber 那条线见另一场:它把渲染拆成可中断的工作单元,调度器用宏任务 + 时间片在空闲时推进,所以「空闲时候调度」指的是 render 阶段用完时间片就把主线程还给浏览器。useState 能记住上一次的值,是因为 hook 状态并不存在组件函数里,而是按调用顺序挂在该 fiber 的 memoizedState 链表上——所以 hook 不能写在条件或循环里,顺序一变状态就错位。React.lazy 配合 Suspense 的原理是:lazy 返回一个带状态的特殊对象,首次渲染时它抛出一个 promise(Suspense 捕获后显示 fallback),模块加载完再重新渲染;动态导入 import() 在编译后就是被拆成一个独立 chunk 的异步加载函数(webpack 里是 __webpack_require__.e 加 JSONP 回调),所以「编译后的代码长什么样」要看打包器怎么实现分包,核心是运行时按需注入 script 并等回调。

资源与缓存:preload、304 与前端的几层缓存

preload 是告诉浏览器「这个资源本轮就会用到,优先下载」,会把资源提到高优先级并保持正确的请求上下文(字体、脚本、样式常用);prefetch 是「下一轮可能会用到」,在浏览器空闲时以低优先级下载并放进缓存。两者都可能被误用:preload 了却不用的资源会在控制台告警并浪费带宽优先级,prefetch 过度会抢首屏带宽。缓存要分成几层讲:HTTP 层(强缓存与协商缓存)、浏览器存储层(localStorage / sessionStorage / IndexedDB / Cache Storage)、内存层(模块内变量、SWR 类的数据缓存)以及 SSR/边缘层(CDN 缓存、服务端数据缓存)。

304 与「服务端对应的 headers」要答得精确:首次 200 响应里服务端要给 ETag 或 Last-Modified 作为校验基线,浏览器下次请求带 If-None-Match / If-Modified-Since,服务端比对未变化就返回 304,不返回 body。因此服务端要做的两件事是「首次给出校验字段」和「收到条件请求时正确比对并回 304」,Nginx 对静态文件默认会给 ETag 与 Last-Modified。要补的坑是:只配 Last-Modified 时,内容没变但文件 mtime 变了(重新部署、拷贝)会误判成已修改,所以 ETag 优先。缓存控制相关 API 里,Cache-Control 指令要能区分 max-age、immutable、no-cache(可以缓存但每次必须校验)、no-store(完全不许缓存)、stale-while-revalidate(先给旧内容、后台刷新),还有 Vary 会影响缓存键(带 Vary: Cookie 基本等于缓存失效)。

Vue 响应式与状态管理选型

Vue2 用 Object.defineProperty 递归把 data 里的属性改成 getter/setter,问题有三个:新增或删除属性监听不到(要 $set / $delete)、数组索引与 length 改不动(靠重写七个数组方法补)、初始化时要递归遍历所有层级(大对象首次渲染成本高),而且没法处理 Map/Set。Vue3 换成 Proxy:能拦截新增、删除、in、ownKeys,覆盖数组与集合类型,而且递归是懒的(访问到哪层包哪层)。被追问「Proxy 的核心缺陷」时可以从数据类型切入:Proxy 只能代理对象,原始值必须有 ref 这层包装才能被追踪;对 Date、Map/Set 这类内部槽对象需要专门的处理分支(Vue3 用 collectionHandlers);对 class 私有字段与某些内置对象的拦截行为要小心;旧浏览器不支持且无法完整 polyfill。上一场常考的 ref 与 reactive 取舍也在这里复用:reactive 解构丢响应、整体替换丢响应,ref 靠 .value 容器规避。

状态管理选型上,zustand 与 useContext 的差别可以从「订阅粒度」和「更新链路」两条讲:Context 是「值变了,所有消费者一起重渲染」,天然不支持按字段订阅,要避免全量重渲染就得手工拆 Context、配合 memo;zustand 把状态放在组件树外的 store 里,组件用 selector 订阅,只有选中的切片变化才触发对应组件,而且能在组件外读写(非 React 环境也能用),没有 Provider 嵌套问题。代价是它不参与 React 的并发特性调度、调试要靠 devtools 中间件,而 Context 适合低频、全局且几乎不变的值(主题、语言、当前用户)。手写 Store 那题按发布订阅实现即可:create 里存 state 与一组监听者,getStore 返回当前快照,dispatch 更新 state 后同步通知所有 listener;要记得提供 subscribe 并返回取消订阅函数,dispatch 里用浅比较避免无变化也通知,这是面试官最容易追问的两点。

页面性能与移动端体验:指标、LCP 与滚动

性能指标要能分组说:加载与首屏(TTFB、FCP、LCP)、稳定性(CLS)、交互(FID 已被 INP 取代、TBT 作为实验室指标)。指标获取分两条路:实验室用 Lighthouse、Performance 面板或 PerformanceObserver 手动打点,线上真实用户数据用 web-vitals 上报到监控,看 p75、p95 并按机型、网络、地区分层,否则平均值会把长尾藏起来。LCP 优化要按 LCP 的四个组成部分对症下药:TTFB 高就查服务端与 CDN、DNS 和 TLS 用 preconnect 提前;资源加载延迟就用 preload 提前关键图、fetchpriority="high",别让首屏图懒加载;资源加载耗时靠压缩(AVIF/WebP)、按尺寸出图、CDN 就近;元素渲染延迟则要减少阻塞渲染的 CSS 与同步脚本、用 font-display: swap 避免字体阻塞。量化效果要给前后对比和观测口径(同一机型、同一网络、p75),只说「感觉快了」等于没说。

移动端的滚动丝滑问题,答案要落到「谁在滚动」:H5 页面优先用原生滚动(-webkit-overflow-scrolling: touch 早已默认),避免用 overflow: hidden 加 transform 自己实现滚动;要阻止滚动穿透就用 overscroll-behavior: contain,滚动过程中只做 transform/opacity 这类合成层动画、不要触发 layout(读写分离,别在 scroll 回调里连续 getBoundingClientRect),高频监听用 passive: true,惯性滚动的 scroll 事件在 iOS 上频率极高,要节流或用 rAF 做采样。分辨率适配讲三件事:视口 meta viewport 与 width=device-width、rem/vw 的等比缩放方案(以设计稿宽度为基准,根字号或 vw 单位换算)、以及 1px 边框与安全区(env(safe-area-inset-*))这类细节。bridge 则按「容器给 H5 的能力」列:导航与返回、登录态与用户信息、分享、支付、相册与相机、定位、剪贴板、埋点与降级方案,还要说清双向通信(原生调 JS 用注入全局方法或 postMessage、JS 调原生用 window.webkit.messageHandlers 或 JSBridge 的 URL scheme 拦截),以及 iOS 与 Android 两套实现的差异。

网络与安全:TCP 的可靠、跨域与 XSS/CSRF

TCP 的「可靠」要拆成四件机制答:一是序号与确认(ACK),每个字节有序号,接收方确认;二是超时重传与快速重传(收到三个重复 ACK 就立刻重传,不等超时);三是滑动窗口做流量控制,接收方通过窗口字段告诉发送方还能收多少,避免把对端缓冲打爆;四是拥塞控制(慢启动指数增长、拥塞避免线性增长、快恢复),避免把中间链路打爆。三次握手、四次挥手按标准答案讲,重点是「为什么不能两次」(防止历史失效的 SYN 让服务端建立无人使用的连接,且三次才能双向确认收发能力)和 TIME_WAIT 等 2MSL 的作用。QUIC 基于 UDP 重做这套机制、把握手和加密合并,是常被顺带问到的加分项。

跨域的根因是同源策略(协议、域名、端口任一不同即跨源),解决方案按优先级:CORS(服务端授权,带凭证时必须指定具体源 + Allow-Credentials)、开发期用代理把请求转成同源、生产用同域反代或 BFF 收敛接口,以及 postMessage 做跨窗口通信;document.domain 已废弃,JSONP 只作历史兼容。安全那两条要分清:XSS 是「把不可信内容当代码执行」,分存储型、反射型、DOM 型,防御靠输出编码与上下文相关的转义、Content-Security-Policy 限制脚本来源、HttpOnly 防止 Cookie 被读、以及对富文本做白名单过滤;CSRF 是「冒用你的登录态发请求」,防御靠 SameSite Cookie、校验 Origin/Referer、CSRF Token,以及关键操作二次验证——注意 CSRF Token 不能放在 Cookie 里读给 JS,否则被 XSS 一起绕过。JS 内存泄漏「定位到哪一行」要答方法论:先判断是持续增长还是锯齿(GC 后不回落才算泄漏),用 Performance 面板做堆快照对比(Allocation instrumentation on timeline 或对比两次 snapshot 的 retained size),DevTools 里看 Detached DOM 树与事件的引用链,线上则靠监控告警 + 定期快照。常见来源是未解绑的定时器与事件监听、闭包持有大对象、全局缓存无上限、ResizeObserver/IntersectionObserver 没断开,以及脱离 DOM 但被 JS 引用的节点。

手撕与算法:从发布订阅到动态规划

发布订阅要写成一个类:on 注册(同名事件存数组)、off 删除、emit 拷贝一份监听器列表再遍历(避免回调里增删导致漏发或死循环)、once 用包装函数在执行前先 off,最好再支持返回取消订阅的函数。追问一般落在「emit 时某个回调抛错怎么办」(单个 try/catch 隔离,别让一个订阅者影响其它)和「和 Promise 的关系」(Promise 的 then 本质也是一种订阅)。手写 Store 与发布订阅同源,重点是同步通知与浅比较。括号生成用回溯:维护已用的左括号数和右括号数,左括号没到 n 就加左,右括号少于左括号才能加右,走到 2n 收结果——这题的考点是剪枝条件而不是递归本身,写完要说清复杂度是第 n 个卡特兰数。链表判环用快慢指针,追问「找出环的入口」就再加一步:相遇后把一个指针放回头部、两个都每次走一步,再次相遇即入口;要能解释为什么(设头到入口 a、入口到相遇点 b、环长 L,则 a = kL - b)。字母异位词用定长窗口计数(26 位数组或哈希表 + 差值计数),窗口每滑动一格只更新进出的两个字符,避免每次重建计数表。上楼梯方案数是斐波那契,手写时注意用滚动变量把空间降到 O(1),并顺一句「这是完全背包或排列型 DP 的退化形式」,能显示你不是背题。