前端八股文面经大全:TME QQ音乐前端二面(2026-04-22)·面经深度解析

前言

大家好,我是木斯佳。

相信很多人都感受到了,在AI浪潮的席卷之下,前端领域的门槛在变高,纯粹的"增删改查"岗位正在肉眼可见地减少。曾经热闹非凡的面经分享,如今也沉寂了许多。但我们都知道,市场的潮水退去,留下的才是真正在踏实准备、努力沉淀的人。学习的需求,从未消失,只是变得更加务实和深入。

这个专栏的初衷很简单:拒绝过时的、流水线式的PDF引流贴,专注于收集和整理当下最新、最真实的前端面试资料。我会在每一份面经和八股文的基础上,尝试从面试官的角度去拆解问题背后的逻辑,而不仅仅是提供一份静态的背诵答案。无论你是校招还是社招,目标是中大厂还是新兴团队,只要是真实发生、有价值的面试经历,我都会在这个专栏里为你沉淀下来。专栏快速地址

温馨提示:市面上的面经鱼龙混杂,甄别真伪、把握时效,是我们对抗内卷最有效的武器。

面经原文内容

📍面试公司:TME QQ音乐

🕐面试时间:4月22日下午3点,时长1小时

💻面试岗位:前端暑期二面

📝面试体验:道心破碎,项目深度拷问,几乎无八股无手撕

❓面试问题:

  1. 自我介绍
  2. 虚拟列表怎么实现的
  3. 一道性能指标采集代码找错误(用户未回忆出具体代码)
  4. 文件上传是怎么实现的
  5. 大文件分片上传时,计算 5MB 分片 MD5 大概要多久
  6. 如果文件很大,计算完整文件 MD5 很耗时,有什么性能优化方案
  7. Web Worker 在大文件 MD5 计算里能怎么用
  8. 服务端保存所有分片索引和分片文件,会不会导致碎片文件越来越多
  9. 分片合并完成后,服务端临时分片目录应该怎么清理
  10. 如果清理了分片,下次上传同一个文件还能不能做分片级别的秒传
  11. 秒传应该基于完整文件 hash 还是分片 hash
  12. 服务端怎么设计分片管理,才能避免既存完整文件又存所有分片造成空间浪费
  13. 如果两个文件部分分片相同、整体文件不同,怎么判断和复用分片
  14. 歌曲列表页点击歌曲后,如何打开一个独立播放页
  15. 如果播放页已经存在,列表页怎么通知已有播放页切换歌曲
  16. 怎么判断播放页是否已经存在或是否被关闭
  17. 如何用 LocalStorage 实现跨页面通信
  18. 如何用 LocalStorage 实现页面间心跳检测
  19. LocalStorage 轮询方案有什么性能问题
  20. 除了 LocalStorage,跨页面通信还有哪些更好的方案
  21. postMessage 和 Service Worker 怎么用于跨页面通信
  22. 歌曲列表中大量图片加载时,如何先展示占位图
  23. 图片加载成功后怎么切换为真实图片
  24. 图片加载失败后怎么展示失败图
  25. 如何通过图片的 load 和 error 事件判断加载状态
  26. 你接触过 React Native 或 Flutter 这类跨端技术吗
  27. Vite 相比 Webpack,为什么开发阶段启动更快
  28. Webpack 能不能也配置成使用 ES Module
  29. Vite 的热更新 HMR 是怎么实现的
  30. WebSocket 和 SSE 有什么区别

来源:牛客网 前端死了咩

💡 木木有话说(刷前先看)

TME QQ音乐这场二面,是一场"实战场景深度拷问"。30个问题中,前13题围绕大文件上传/分片/MD5/秒传/服务端设计 层层递进,后10题围绕跨页面通信/图片加载 场景展开,最后是工程化基础。面试官显然不满足于"会不会用",而是要考察你在大文件上传、跨页面通信等真实场景下的系统设计能力 。用户反馈"道心破碎",可见难度之高。这份面经适合有一定项目经验、准备冲击中大厂的同学反复研读。


📝 TME QQ音乐前端二面·深度解析

🎯 面试整体画像

维度 特征
面试风格 实战场景深挖型 + 系统设计型 + 前后端协作型
难度评级 ⭐⭐⭐⭐⭐(五星,大文件上传设计链路极深)
考察重心 大文件分片上传、MD5计算优化、秒传设计、跨页面通信、图片加载、Vite原理
特殊之处 无八股无手撕,围绕真实业务场景层层追问设计细节

🔍 逐题深度解析

二、虚拟列表怎么实现的

回答思路:参考之前面经。核心是只渲染可视区域,动态计算起始索引。

javascript 复制代码
// 核心实现
function VirtualList({ items, itemHeight, containerHeight }) {
  const [startIndex, setStartIndex] = useState(0)
  const visibleCount = Math.ceil(containerHeight / itemHeight)
  
  const handleScroll = (e) => {
    const scrollTop = e.target.scrollTop
    const newStartIndex = Math.floor(scrollTop / itemHeight)
    setStartIndex(newStartIndex)
  }
  
  const visibleItems = items.slice(startIndex, startIndex + visibleCount)
  const paddingTop = startIndex * itemHeight
  
  return (
    <div onScroll={handleScroll} style={{ height: containerHeight, overflow: 'auto' }}>
      <div style={{ paddingTop, height: items.length * itemHeight }}>
        {visibleItems.map(item => <div key={item.id}>{item.content}</div>)}
      </div>
    </div>
  )
}

四、文件上传是怎么实现的

回答思路:分片上传 + 断点续传 + 秒传。

核心流程

  1. 文件分片(Blob.prototype.slice
  2. 计算文件/分片MD5(用于秒传和校验)
  3. 并发上传分片(控制并发数)
  4. 服务端记录已上传分片,支持断点续传
  5. 全部分片上传完成后,服务端合并

五、大文件分片上传时,计算 5MB 分片 MD5 大概要多久

回答思路 :取决于设备性能和算法,大约20-100ms

  • 现代PC:5MB数据约20-40ms
  • 移动端/低端设备:50-100ms
  • 使用Web Crypto API比纯JS实现快2-3倍

六、如果文件很大,计算完整文件 MD5 很耗时,有什么性能优化方案

优化方案

  1. 抽样计算:只计算开头、中间、结尾部分数据,而非全量
  2. 增量计算:读取文件流,边读边更新hash,不一次性加载到内存
  3. Web Worker:在Worker线程计算,不阻塞主线程
  4. 分片复用:使用分片MD5,完整MD5由分片MD5组合得到
  5. 采样秒传:先快速计算采样hash,命中后再计算完整hash
javascript 复制代码
// 增量计算示例
async function computeMD5(file) {
  const chunkSize = 1024 * 1024 // 1MB
  const hasher = new CryptoJS.algo.MD5()
  
  for (let i = 0; i < file.size; i += chunkSize) {
    const chunk = file.slice(i, i + chunkSize)
    const buffer = await chunk.arrayBuffer()
    hasher.update(CryptoJS.lib.WordArray.create(buffer))
    // 更新进度
  }
  return hasher.finalize().toString()
}

七、Web Worker 在大文件 MD5 计算里能怎么用

回答思路:将耗时的MD5计算移到Worker线程,避免阻塞UI。

javascript 复制代码
// main.js
const worker = new Worker('md5-worker.js')
worker.postMessage({ file })
worker.onmessage = (e) => {
  console.log('MD5:', e.data)
}

// md5-worker.js
self.onmessage = async (e) => {
  const file = e.data.file
  const md5 = await computeMD5(file)
  self.postMessage(md5)
}

优势:UI不卡顿,用户可继续操作;可同时计算多个文件。


八~十三:大文件分片服务端设计链路

8. 服务端保存分片会导致碎片文件越来越多吗?

  • 。每个未合并的分片都会占用存储空间,尤其是上传中断、未完成合并的分片成为碎片。

9. 分片合并完成后,服务端临时分片目录应该怎么清理?

  • 合并后立即删除临时分片
  • 定时任务:扫描超时未合并的分片(如上传中断超过24小时),自动删除
  • 上传取消时主动触发删除

10. 清理了分片,下次上传同一个文件还能做分片级别的秒传吗?

  • 不能。秒传依赖于分片hash,分片被删除后无法定位
  • 解决方案 :上传完成后保存分片hash索引,合并后保留分片hash记录但不保留分片文件

11. 秒传应该基于完整文件 hash 还是分片 hash?

  • 两者结合 :完整文件hash用于整文件秒传 ,分片hash用于断点续传和分片级秒传

12. 服务端怎么设计分片管理,避免既存完整文件又存分片造成空间浪费?

  • 分片重用:完整文件存储后,将分片hash指向完整文件的位置
  • 引用计数:同一分片被多个文件共享时,计数管理
  • 去重存储:分片内容唯一存储,文件由分片引用组成

13. 两个文件部分分片相同、整体文件不同,怎么判断和复用分片?

  • 分片级去重:每个分片独立存储,用hash标识
  • 文件分片表:文件A:[hash1, hash2, hash3],文件B:[hash1, hash4, hash5]
  • 复用逻辑:上传分片前检查hash是否已存在,存在则跳过

十四、歌曲列表页点击歌曲后,如何打开一个独立播放页

方案

  • window.open('player.html') 打开新标签页
  • 如果是SPA,可以用路由跳转 + 新标签页

十五、如果播放页已经存在,列表页怎么通知已有播放页切换歌曲

跨页面通信方案

  • LocalStorage + storage事件(最常用)
  • BroadcastChannel(现代浏览器推荐)
  • postMessage(需维护目标窗口引用)
  • Service Worker(复杂,用于离线场景)
javascript 复制代码
// 列表页
localStorage.setItem('play-song', JSON.stringify({ id: 123, name: '稻香' }))

// 播放页
window.addEventListener('storage', (e) => {
  if (e.key === 'play-song') {
    const song = JSON.parse(e.newValue)
    playSong(song)
  }
})

十六、怎么判断播放页是否已经存在或是否被关闭

方案

  • 心跳检测:播放页每N秒写入LocalStorage时间戳,列表页轮询检查,超时则认为已关闭
  • BroadcastChannel :监听close事件
  • SharedWorker:维护活动页面计数

十七、如何用 LocalStorage 实现跨页面通信

javascript 复制代码
// 发送消息
localStorage.setItem('message', JSON.stringify({ type: 'play', data: song }))

// 接收消息
window.addEventListener('storage', (e) => {
  if (e.key === 'message') {
    const { type, data } = JSON.parse(e.newValue)
    handleMessage(type, data)
  }
})

十八、如何用 LocalStorage 实现页面间心跳检测

javascript 复制代码
// 播放页:每5秒更新时间戳
setInterval(() => {
  localStorage.setItem('player_heartbeat', Date.now())
}, 5000)

// 列表页:轮询检查
setInterval(() => {
  const lastHeartbeat = localStorage.getItem('player_heartbeat')
  if (lastHeartbeat && Date.now() - lastHeartbeat > 10000) {
    console.log('播放页已关闭')
    localStorage.removeItem('player_heartbeat')
  }
}, 5000)

十九、LocalStorage 轮询方案有什么性能问题

问题

  • 主线程阻塞storage事件监听本身无性能问题,但轮询检查会占用主线程
  • 频繁读写:高频率写入localStorage会有同步I/O开销
  • 不适合高实时性场景:延迟约几十毫秒

二十~二十一、更好的跨页面通信方案

方案 优点 缺点
BroadcastChannel API简单,低延迟 同源限制,不支持跨域
postMessage 双向通信,跨域 需维护窗口引用
SharedWorker 可维护状态,支持多页面 实现复杂
Service Worker 离线支持,可做中转 生命周期管理复杂

BroadcastChannel示例

javascript 复制代码
// 列表页
const channel = new BroadcastChannel('player')
channel.postMessage({ type: 'play', song })

// 播放页
const channel = new BroadcastChannel('player')
channel.onmessage = (e) => {
  playSong(e.data.song)
}

二十二~二十五:图片加载占位图方案

javascript 复制代码
function LazyImage({ src, alt }) {
  const [status, setStatus] = useState('loading')
  
  useEffect(() => {
    const img = new Image()
    img.src = src
    img.onload = () => setStatus('success')
    img.onerror = () => setStatus('error')
  }, [src])
  
  if (status === 'loading') return <Skeleton />
  if (status === 'error') return <ErrorIcon />
  return <img src={src} alt={alt} />
}

二十七~二十九:Vite vs Webpack

27. Vite为什么启动更快?

  • 利用浏览器ESM,开发环境不打包,直接按需编译
  • 预构建依赖(esbuild),比Webpack快10-100倍

28. Webpack能不能配置成使用ES Module?

  • ,通过experiments.outputModule: true,但生态兼容性一般

29. Vite HMR怎么实现的?

  • 基于ESM的HMR,只更新变更的模块
  • Webpack HMR需要重新打包相关模块

三十、WebSocket和SSE区别

维度 SSE WebSocket
方向 单向(服务端→客户端) 双向
协议 HTTP WS/WSS
自动重连 内置 需手动实现
二进制数据 需编码 原生支持

📚 知识点速查表

知识点 核心要点
虚拟列表 可视区域渲染、动态起始索引
大文件上传 分片(slice)、MD5、断点续传、秒传
MD5优化 Web Worker、增量计算、采样
分片服务端设计 临时分片清理、分片hash复用、引用计数
跨页面通信 LocalStorage+storage事件、BroadcastChannel、postMessage
LocalStorage心跳 定期写时间戳,轮询检测超时
图片加载 load/error事件、占位图/失败图
Vite启动快 利用ESM不打包、esbuild预构建
SSE vs WS 单向/双向、协议、自动重连

📌 最后一句:

TME QQ音乐这场二面,是一场"实战场景课"。从大文件上传的分片MD5计算、秒传设计、服务端分片管理,到跨页面通信、图片加载、构建工具原理,面试官用30个问题构建了一个完整的前端知识体系树 。用户感慨"道心破碎",但这样的面试即使挂了,也是收获巨大的------它划出了大厂对前端工程师的能力期望:不仅要会写代码,更要懂系统设计、懂前后端协作、懂性能优化

相关推荐
敲代码的彭于晏2 小时前
感谢掘金,我的书又出版了
前端·vue.js·react.js
龙猫里的小梅啊2 小时前
CSS(五)CSS盒模型
前端·css·html
明月_清风3 小时前
Nginx 生产环境配置完全指南:从安全加固到性能调优
前端·nginx
用户600071819103 小时前
【翻译】用 Reanimated CSS 动画为 TextInput 添加发光效果
前端
李剑一3 小时前
前后端命名冲突?驼峰与下划线的统一方案(附可直接复用代码)
前端
用户11481867894843 小时前
Git Stash 丢失后的完整找回指南
前端·git
代码不加糖3 小时前
2026 React 面试“通关秘籍”:高频 12 问 + 深度解析(含Hooks源码思想)
前端·react.js·面试
我滴老baby3 小时前
ReAct推理模式详解让智能体学会边思考边行动
前端·react.js·前端框架
菜鸟小码3 小时前
MapReduce 核心阶段深度解析:Map 阶段与 Reduce 阶段的作用及执行流程
前端·javascript·mapreduce