跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScriptNode.js大前端算法

字节跳动音视频前端一面面经与深度解析

字节跳动音视频前端岗位面试真题及深度解析。内容涵盖首屏加载优化(FCP)、ESM 兼容性处理、代码分割策略、不定高虚拟列表原理、Next.js 渲染模式选择及应用场景、图片组件优化及 WebP 格式降级方案。通过实际代码示例和架构分析,帮助开发者理解大厂对性能优化与工程化能力的考察重点。

CloudNative发布于 2026/4/6更新于 2026/5/2031 浏览
字节跳动音视频前端一面面经与深度解析

面经原文内容

📍面试公司:字节跳动

🕐面试时间:3 月 3 日

💻面试岗位:音视频前端(春招)

❓面试问题:

  1. 自我介绍
  2. 用了哪些方法使 FCP 渲染耗时缩短近 1s
  3. 有没有遇到过哪个包不支持 ESM 的,你是怎么处理的
  4. 你进行代码分割的思路是什么
  5. 不定高的虚拟列表的实现原理是什么
  6. NextJS 有哪些渲染模式,分别介绍一下
  7. 你们的应用用的是哪种
  8. NextJS 中有一个内置的图片优化组件,它做了哪些优化
  9. 让你优化图片显示你怎么优化
  10. webp 格式的图片有兼容性问题吗,怎么做降级处理

📝 字节跳动音视频前端一面·深度解析

🎯 面试整体画像

维度特征
公司定位字节跳动 - 音视频方向
面试风格项目深潜型 + 场景追问型
难度评级⭐⭐⭐⭐(四星)
考察重心性能优化、工程化、Next.js、图片处理

💡 面经关键点解读

面试官的潜台词:音视频业务对性能要求极高,所以 FCP 优化要问到具体数值;项目中遇到过的工程化问题能看出你的实战深度;虚拟列表是长列表场景的必备技能;Next.js 是字节很多中台项目的首选框架;图片优化直接影响用户体验。这些问题环环相扣,考察的是一个前端工程师的全链路优化能力。


🔍 逐题深度解析

一、FCP 优化
问题:用了哪些方法使 FCP 渲染耗时缩短近 1s

FCP(First Contentful Paint)是衡量首屏加载体验的核心指标。

// 1. 关键 CSS 内联
// 将首屏所需 CSS 直接内联到 HTML,避免网络请求
<style>
.header {height: 60px; background: #fff;}
.hero {height: 400px; background:url('hero-small.jpg');}
/* 只包含首屏样式,约 2KB */
</style>
// 2. 预加载关键资源
// 告诉浏览器优先下载关键资源
<link rel="preload" href="critical.js" as="script">
<link rel="preload" href="hero.webp" as="image">
<link rel="preconnect" href="https://fonts.googleapis.com">
// 3. 图片优化
// 使用 WebP 格式 + 响应式图片
<picture>
<source srcset="hero-320.webp 320w, hero-640.webp 640w" type="image/webp">
<img src="hero-640.jpg" srcset="hero-320.jpg 320w, hero-640.jpg 640w" loading="eager">
</picture>
// 4. 字体优化
@font-face { font-family:'CustomFont';
src:url('font.woff2')format('woff2'); 
font-display: swap;
// 文本立即用降级字体显示,加载后替换}
// 5. 骨架屏
<div class="skeleton">
<div class="skeleton-header"></div>
<div class="skeleton-content"></div>
</div>
// 6. 移除阻塞渲染的 JS
<script src="analytics.js" async defer></script>
// 7. 服务端渲染/静态生成
// Next.js 的 SSG/SSR 直接返回 HTML
二、ESM 兼容性问题
问题:有没有遇到过哪个包不支持 ESM 的,你是怎么处理的

在工程化实践中,经常会遇到一些老包只提供 CommonJS 版本,导致 Tree Shaking 失效或 Next.js 报错。

// 问题示例:some-old-package 只提供 CommonJS
const { debounce } = require('some-old-package')
// ❌

// 解决方案 1:next-transpile-modules(Next.js 专用)
// next.config.js
const withTM = require('next-transpile-modules')(['some-old-package', 'another-cjs-pkg'])
module.exports = withTM({/* 其他配置 */})

// 解决方案 2:webpack 配置(通用)
module.exports = {
  webpack: (config) => {
    config.module.rules.push({
      test: /\.js$/,
      include: /node_modules\/(some-old-package|another-pkg)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: ['@babel/plugin-transform-modules-commonjs']
        }
      }
    })
    return config
  }
}

// 解决方案 3:动态导入(运行时降级)
const somePackage = await import('some-old-package').then(m => m.default || m)

// 解决方案 4:patch-package 直接修改
// 创建补丁文件 patches/some-old-package+1.2.3.patch
// 手动修改导出方式为 ESM

// 解决方案 5:找替代品
// 如果以上都不行,考虑换一个支持 ESM 的库

实际案例:曾遇到 marked 库某个版本 ESM 导出有问题,最终锁定到兼容版本并配置 transpile 解决。


三、代码分割思路
问题:你进行代码分割的思路是什么

代码分割的核心是'按需加载',让用户只下载当前页面所需的代码。

// 1. 路由级别分割(最常用)
// React
const Home = lazy(() => import('./pages/Home'))
const About = lazy(() => import('./pages/About'))
// Vue
const routes = [{
  path: '/',
  component: () => import('@/pages/Home.vue')
}]

// 2. 组件级别分割
const Editor = dynamic(() => import('@/components/Editor'), {
  loading: () => <Loading />, ssr: false // 不需要服务端渲染的组件
})

// 3. 三方库分割(webpack 配置)
splitChunks: {
  chunks: 'all',
  cacheGroups: {
    vendor: {
      test: /[\\/]node_modules[\/]/,
      name: 'vendors',
      priority: 10
    },
    ui: {
      test: /[\\/]node_modules[\/](antd|element-ui)[\/]/,
      name: 'ui-libs',
      priority: 20
    }
  }
}

// 4. 动态导入(条件性加载)
if(userHasPermission('edit')){
  import('./editor.js').then(module => {
    module.initEditor()
  })
}

// 5. 预加载策略
<link rel="prefetch" href="next-page.js">
// 或使用 IntersectionObserver 预加载
observer.observe(linkElement)
// 当链接进入视口时预加载

// 6. 监控分析
// 使用 webpack-bundle-analyzer 定期检查

分割思路总结:先路由后组件,三方库单独打包,动态功能按需加载,空闲时间预加载。


四、不定高虚拟列表
问题:不定高的虚拟列表的实现原理是什么

虚拟列表的核心是只渲染可视区域内的元素。不定高比定高复杂,因为无法预知每个元素的高度。

// 核心数据结构:维护每个元素的位置信息
class VirtualList {
  constructor() {
    this.positions = [] // [{ top, bottom, height }]
    this.totalHeight = 0
  }

  // 1. 初始化:使用预估高度
  initPositions(items, estimatedHeight = 100) {
    let top = 0
    this.positions = items.map((_, index) => {
      const height = estimatedHeight
      const position = { index, height, top, bottom: top + height }
      top += height
      return position
    })
    this.totalHeight = top
  }

  // 2. 动态更新:渲染后测量真实高度
  updateHeight(index, realHeight) {
    const pos = this.positions[index]
    const diff = realHeight - pos.height
    if(diff !== 0){
      pos.height = realHeight
      pos.bottom += diff // 更新后续所有元素的位置
      for(let i = index + 1; i < this.positions.length; i++){
        this.positions[i].top += diff
        this.positions[i].bottom += diff
      }
      this.totalHeight += diff
    }
  }

  // 3. 二分查找:快速定位起始索引
  getStartIndex(scrollTop) {
    let left = 0
    let right = this.positions.length - 1
    while(left <= right){
      const mid = Math.floor((left + right)/2)
      const pos = this.positions[mid]
      if(pos.bottom < scrollTop){ left = mid + 1 }
      else if(pos.top > scrollTop){ right = mid - 1 }
      else{ return mid }
    }
    return left
  }

  // 4. 获取可见项
  getVisibleItems(scrollTop, containerHeight) {
    const start = this.getStartIndex(scrollTop)
    const end = this.getStartIndex(scrollTop + containerHeight)
    return this.positions.slice(start, end + 1).map(pos => ({...pos, // 对应的数据项}))
  }
}

// React Hook 版本简化
function useVirtualList(items, itemHeight = 100) {
  const [positions, setPositions] = useState([])
  useEffect(() => {
    // 初始化位置
    let top = 0
    const newPositions = items.map((_, i) => {
      const pos = { top, height: itemHeight, bottom: top + itemHeight }
      top += itemHeight
      return pos
    })
    setPositions(newPositions)
  }, [items])

  const updateItemHeight = (index, height) => {
    setPositions(prev => {
      const newPositions = [...prev]
      const diff = height - newPositions[index].height
      newPositions[index].height = height
      newPositions[index].bottom += diff
      for(let i = index + 1; i < newPositions.length; i++){
        newPositions[i].top += diff
        newPositions[i].bottom += diff
      }
      return newPositions
    })
  }

  return { positions, updateItemHeight }
}

五、Next.js 渲染模式
问题:NextJS 有哪些渲染模式,分别介绍一下

Next.js 提供了多种渲染模式,适应不同场景需求:

模式原理特点适用场景
SSR每次请求时在服务器渲染实时性好、SEO 友好个性化页面、需实时数据
SSG构建时生成静态 HTML极快、可 CDN 缓存博客、文档、营销页
ISR静态生成 + 定期更新兼顾速度与实时性产品页、新闻站
CSR客户端渲染强交互后台管理、个人中心
// SSR - Server-Side Rendering
export async function getServerSideProps(context) {
  // 每次请求执行
  const data = await fetch(`/api/user/${context.params.id}`)
  return { props: { data } }
}

// SSG - Static Site Generation
export async function getStaticProps() {
  // 构建时执行
  const posts = await fetchPosts()
  return { props: { posts } }
}

// ISR - Incremental Static Regeneration
export async function getStaticProps() {
  const data = await fetchData()
  return { props: { data }, revalidate: 60 // 每 60 秒重新生成 }
}

// 动态路由的静态生成
export async function getStaticPaths() {
  const posts = await fetchPostIds()
  const paths = posts.map(p => ({ params: { id: p.id } }))
  return { paths, fallback: 'blocking' } // fallback 处理未生成的路径
}

// CSR - Client-Side Rendering
function Page() {
  const [data, setData] = useState(null)
  useEffect(() => {
    fetchData().then(setData)
  }, [])
  return <div>{data}</div>
}

六、应用渲染模式选择
问题:你们的应用用的是哪种

根据业务场景混合使用:

// 1. 官网/营销页:SSG
// 原因:内容相对固定,需要极致速度和 SEO
export getStaticProps(){...}

// 2. 博客/文档:SSG + ISR
// 原因:内容更新不频繁,但需要实时发布
export getStaticProps({revalidate:3600}){...}

// 3. 用户个人中心:CSR
// 原因:强交互,需要登录态
// 直接客户端渲染

// 4. 详情页:SSR 或 ISR
// 如果内容动态变化快:SSR
// 如果内容变化慢:ISR
export getServerSideProps(){...}

// 5. 混合示例
// pages/index.js - SSG
export getStaticProps(){...}

// pages/product/[id].js - ISR
export getStaticPaths(){...}
export getStaticProps({revalidate:60}){...}

// pages/user/profile.js - CSR
// 不导出任一函数,默认 CSR

选择标准:

  • SEO 要求高 → 用 SSG/SSR
  • 数据实时性要求高 → 用 SSR
  • 速度要求高、数据变化慢 → 用 SSG
  • 需要登录态 → 用 CSR
  • 数据变化快但能接受延迟 → 用 ISR

七、Next.js 图片优化组件
问题:NextJS 中有一个内置的图片优化组件,它做了哪些优化
import Image from 'next/image'
<Image src="/hero.jpg" alt="Hero" width={1200} height={600} priority quality={75} placeholder="blur" blurDataURL="data:image/jpeg;base64,/9j/..."/>

// 1. 响应式图片
// 自动生成多尺寸,设置 srcset
// 输出:<img srcset="/_next/image?w=640 640w,/_next/image?w=750 750w,/_next/image?w=828 828w" />

// 2. 格式优化
// 根据浏览器支持自动选择 WebP/AVIF
// Chrome 收到 WebP,Safari 收到 JPEG

// 3. 懒加载
// 默认启用 IntersectionObserver
// 进入视口才加载

// 4. 预加载关键图片
// priority 属性会添加到预加载清单
<link rel="preload" as="image" href="/hero.jpg">

// 5. 防止布局偏移
// 必须指定宽高,自动计算 aspect-ratio
<div style="aspect-ratio: 1200/600"><img ...></div>

// 6. 占位图 placeholder="blur"
// 显示模糊占位 blurDataURL // 自定义 base64 占位图

// 7. 图片域名配置
// next.config.js
module.exports = {
  images: {
    domains: ['example.com','cdn.example.com'],
    formats: ['image/webp','image/avif']
  }
}

// 8. 优化效果
// 体积:JPEG 200KB → WebP 60KB(-70%)
// 加载:原本需要手动处理的工作自动完成

八、图片显示优化
问题:让你优化图片显示你怎么优化
// 1. 格式选择
// WebP > AVIF > JPEG/PNG
// WebP 比 JPEG 小 25-35%,比 PNG 小 80%

// 2. 响应式图片
<img src="image-800.jpg" srcset=" image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w " sizes=" (max-width: 500px) 400px,(max-width: 900px) 800px, 1200px " >

// 3. 懒加载
<img loading="lazy" src="image.jpg">

// 4. 渐进式加载
function ProgressiveImage({ src, placeholder }) {
  const [currentSrc, setCurrentSrc] = useState(placeholder)
  useEffect(() => {
    const img = new Image()
    img.src = src
    img.onload = () => setCurrentSrc(src)
  }, [src])
  return (
    <img src={currentSrc} style={{filter: currentSrc === placeholder ?'blur(10px)':'none'}}/>
  )
}

// 5. 使用 CDN
// 加上图片处理参数 https://cdn.example.com/image.jpg?w=800&q=75&format=webp 

// 6. 缓存策略
// 强缓存 + hash 文件名 Cache-Control: max-age=31536000
// image-8f3c9d.jpg

// 7. 预加载关键图片
<link rel="preload" as="image" href="hero.jpg">

// 8. 使用 Intersection Observer
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if(entry.isIntersecting){
      const img = entry.target
      img.src = img.dataset.src
      observer.unobserve(img)
    }
  })
})

九、WebP 兼容性降级
问题:webp 格式的图片有兼容性问题吗,怎么做降级处理
// 1. picture 标签(最推荐)
<picture>
<source srcset="image.webp" type="image/webp">
<source srcset="image.jp2" type="image/jp2">
<img src="image.jpg" alt="fallback"></picture>

// 2. 特性检测
function supportsWebP(){
  const canvas = document.createElement('canvas')
  if(canvas.toDataURL){
    return canvas.toDataURL('image/webp').indexOf('image/webp')===0
  }
  return false
}
// 使用
const src = supportsWebP()?'image.webp':'image.jpg'

// 3. 服务端检测
app.get('/image',(req, res)=>{
  const accept = req.headers['accept']
  if(accept && accept.includes('image/webp')){
    res.setHeader('Content-Type','image/webp')
    res.sendFile('image.webp')
  }else{
    res.sendFile('image.jpg')
  }
})

// 4. Modernizr
if(Modernizr.webp){
  // 使用 WebP
}else{
  // 使用降级格式
}

// 5. Next.js 自动处理
<Image src="/image.jpg"/>
// 自动检测 Accept 头,返回对应格式

// 6. 批量转换工具
// 构建时生成 webp 版本
const imagemin = require('imagemin')
const imageminWebp = require('imagemin-webp')
await imagemin(['images/*.{jpg,png}'],{
  destination:'public/images',
  plugins:[imageminWebp({quality:75})]
})

// 7. 动态加载
const webpSupported = await checkWebPSupport()
const imageUrl = webpSupported ?'/img.webp':'/img.jpg'

📚 知识点速查表

知识点核心要点
FCP 优化关键 CSS、预加载、图片优化、字体优化、骨架屏
ESM 兼容transpile、webpack 配置、动态导入、patch-package
代码分割路由级、组件级、三方库、动态导入、预加载
不定高虚拟列表预估高度、动态更新、二分查找、位置数组
Next 渲染模式SSR(实时)、SSG(静态)、ISR(增量)、CSR(客户端)
图片优化组件响应式、格式转换、懒加载、预加载、布局稳定
图片优化格式选择、响应式、懒加载、CDN、缓存
WebP 降级picture 标签、特性检测、服务端判断、Modernizr

总结:

字节的这场面试,从性能优化到工程化再到框架原理,考察非常全面。音视频业务对性能的极致追求,决定了这些问题都是真实工作中每天要面对的。能把这些讲清楚,说明你已经具备了应对复杂业务场景的能力。

目录

  1. 面经原文内容
  2. 📝 字节跳动音视频前端一面·深度解析
  3. 🎯 面试整体画像
  4. 💡 面经关键点解读
  5. 🔍 逐题深度解析
  6. 一、FCP 优化
  7. 问题:用了哪些方法使 FCP 渲染耗时缩短近 1s
  8. 二、ESM 兼容性问题
  9. 问题:有没有遇到过哪个包不支持 ESM 的,你是怎么处理的
  10. 三、代码分割思路
  11. 问题:你进行代码分割的思路是什么
  12. 四、不定高虚拟列表
  13. 问题:不定高的虚拟列表的实现原理是什么
  14. 五、Next.js 渲染模式
  15. 问题:NextJS 有哪些渲染模式,分别介绍一下
  16. 六、应用渲染模式选择
  17. 问题:你们的应用用的是哪种
  18. 七、Next.js 图片优化组件
  19. 问题:NextJS 中有一个内置的图片优化组件,它做了哪些优化
  20. 八、图片显示优化
  21. 问题:让你优化图片显示你怎么优化
  22. 九、WebP 兼容性降级
  23. 问题:webp 格式的图片有兼容性问题吗,怎么做降级处理
  24. 📚 知识点速查表
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 现代 C++ 中 noexcept 声明的适用场景与核心优势
  • AIRI:基于 AI 大模型构建桌宠虚拟伴侣
  • Python 字节码逆向工具 pycdc:从.pyc 文件恢复源代码
  • 鸿蒙系统卓易通安装应用的通知异常分析
  • 基于 Milvus 混合检索的云厂商文档智能问答系统:Java SpringBoot 实现
  • Stable Diffusion 显存管理技术解析与优化实践
  • 使用 cpolar 内网穿透实现 OpenClaw 远程访问
  • 数据结构:Java 版 ArrayList 与顺序表实现
  • Linux 文件 I/O 本质与内核视角:从 fopen 到 open
  • HTML5 结合 AI 实现智能场景渲染与交互
  • AI 赋能原则 3 解读:可得性时代重写人类能力结构
  • 基于 FPGA 的北斗导航自适应抗干扰算法设计与实现
  • 二分算法实战:A-B 数对与高考志愿问题解析
  • 12 款主流 AIGC 检测与降重工具对比评测
  • 自然语言处理在客户服务领域的应用与实战
  • AI Agent 架构解析:构建 Plan-and-Execute 智能体
  • 基于 Docker 的 Web 应用一键打包为 Android APK 方案
  • ChatGPT 到 AI 大模型私有化部署:企业技术选择分析
  • 电力巡检设备状态检测数据集:缺陷检测与分类
  • VSCode Copilot 登录失败常见原因与解决方案

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online