Skip to content

22 · Web 平台能力(浏览器新特性) ​

本篇解决什么问题: 很多"高级需求"其实浏览器已经内置了,但很多人还在引第三方库。 本篇梳理 Web Components / WebAssembly / Web Workers / Service Worker·PWA / WebRTC / WebGPU, 重点说清什么时候该用、什么时候别碰——以及各自的坑。

📌 原则:平台能力优先。能用原生的就别引库,但要认清原生能力的边界。


开篇速览 ​

能力解决什么成熟可用度典型场景
Web Components框架无关的组件复用✅ 成熟(但生态弱)跨框架组件库、微前端组件共享
WebAssembly让 C/C++/Rust 在浏览器跑✅ 成熟音视频编解码、图像/3D、移植 C++ 库
Web Workers把计算挪出主线程✅ 成熟大数据处理、加密、解析
Service Worker / PWA离线、缓存、安装到桌面✅ 成熟(有坑)离线可用、消息推送
WebRTC浏览器间实时音视频/数据✅ 成熟(复杂)视频会议、屏幕共享、P2P
WebGPU现代 GPU 编程接口⚠️ 逐步普及高性能 3D、端侧推理

一、Web Components:原生组件标准 ​

三块基石:

技术作用
Custom Elements自定义标签 + 生命周期(connectedCallback 等)
Shadow DOM样式与结构隔离,不泄漏到外部
HTML Template(<template> / <slot>)声明式模板与内容分发
js
class MyCard extends HTMLElement {
  constructor() { super(); this.attachShadow({ mode: 'open' }) }
  connectedCallback() {
    this.shadowRoot.innerHTML = `
      <style>.card { border:1px solid #ddd; padding:12px }</style>
      <div class="card"><slot name="title"></slot><slot></slot></div>`
  }
  disconnectedCallback() { /* 清理,防泄漏 */ }
}
customElements.define('my-card', MyCard)

什么时候用 / 别用:

✅ 用❌ 别用
要在 React / Vue / Angular 共用同一套组件只在一个框架内用(框架自己的组件更好用)
微前端里共享基础组件(见 A24)需要复杂状态管理与数据驱动渲染
做 SDK / 第三方嵌入组件需要 SSR(Shadow DOM 的 SSR 很别扭)

⚠️ 痛点:没有数据绑定与响应式、表单集成麻烦、SSR 支持差。 所以 Web Components 更适合"基础展示型组件",不适合承载业务逻辑。


二、WebAssembly(Wasm):让重计算跑满速 ​

是什么:一种二进制指令格式,作为 JS 的补充,在浏览器里以接近原生速度运行。

不是什么:❌ 不是 JS 的替代品,❌ 不能直接操作 DOM(要通过 JS 胶水层)。

js
// 加载并调用 Wasm
const { instance } = await WebAssembly.instantiateStreaming(fetch('/add.wasm'))
instance.exports.add(1, 2)   // 3

适合:

场景例子
计算密集图像/视频编解码(FFmpeg.wasm)、CAD、物理引擎
移植已有 C/C++/Rust 库把成熟库搬到前端,避免重写
游戏引擎Unity / Unreal 导出到 Web

不适合:DOM 操作多的场景(跨 JS/Wasm 边界的调用有开销)、普通 CRUD。

💡 判断标准:计算时间 > 调用边界开销才划算。小任务用 Wasm 反而更慢。


三、Web Workers:把重活挪出主线程 ​

主线程要负责渲染与交互(见 A09 的 16.67ms 帧预算), 长任务会卡住 UI。Worker 提供独立线程。

js
// main.js
const worker = new Worker('/worker.js', { type: 'module' })
worker.postMessage({ cmd: 'parse', data: bigData })
worker.onmessage = e => console.log('结果', e.data)
worker.onerror = e => console.error(e)
worker.terminate()   // ✅ 用完必须销毁

// worker.js
self.onmessage = e => {
  const result = heavyCompute(e.data)
  self.postMessage(result)   // 结构化克隆(可传 Transferable 零拷贝)
}

关键限制(面试常考):

限制说明
无 DOM不能碰 document、window(只有 self)
独立作用域与主线程的变量不共享
通信靠 postMessage默认结构化克隆(有拷贝开销)
无 localStorage可用 IndexedDB

零拷贝技巧:传 Transferable Objects(ArrayBuffer),避免大数组复制:

js
worker.postMessage(buffer, [buffer])   // 第二个参数是"转移"列表

💡 Comlink 这类库把 postMessage 包装成 Promise 调用,开发体验接近本地函数。


四、Service Worker 与 PWA:离线与安装 ​

Service Worker 是运行在浏览器后台的代理,能拦截网络请求。

页面 ──请求──► Service Worker ──► 命中缓存?直接返回 : 走网络并写入缓存
js
// sw.js —— 缓存优先(Cache First)
self.addEventListener('fetch', e => {
  e.respondWith(
    caches.match(e.request).then(hit => hit || fetch(e.request).then(res => {
      const copy = res.clone()
      caches.open('v1').then(c => c.put(e.request, copy))
      return res
    }))
  )
})

PWA 三要素:HTTPS + Web App Manifest + Service Worker。

最大的坑(务必记住):

坑说明
更新滞后旧 SW 会一直控制页面,新 SW 要等所有页面关闭才激活 → 用 skipWaiting() + clients.claim(),或提示用户刷新
缓存脏数据缓存策略写错会导致用户永远看到旧版本 → 必须做版本化缓存名 + 清理旧缓存
调试困难只在生产表现、DevTools 里要勾 "Update on reload"

⚠️ 本项目的前车之鉴:前端缓存失效是发布事故的重灾区,详见 A16 · CI/CD 与部署运维。


五、WebRTC:浏览器间的实时通信 ​

能力:浏览器**点对点(P2P)**传输音视频与任意数据,无需中转服务器(但实际大多需要)。

三个核心 API:

API作用
getUserMedia()拿到摄像头 / 麦克风 / 屏幕
RTCPeerConnection建立 P2P 连接,传输音视频与数据通道
RTCDataChannel传任意数据(低延迟,类似 WebSocket 但 P2P)

必须知道的现实:

  • NAT 穿透需要 STUN(拿公网地址)+ TURN(中继兜底,要花钱)
  • 多人会议通常用 SFU(选择性转发单元)架构,纯 P2P 只适合 2~4 人
  • 信令(SDP 交换)协议不在 WebRTC 标准里,要自己用 WebSocket 实现

六、WebGPU:下一代图形接口 ​

定位:WebGL 的继任者,暴露现代 GPU 能力(类似 Vulkan / Metal / D3D12)。

对比WebGLWebGPU
抽象层次高(OpenGL ES 风格)低(显式命令/管线)
计算着色器❌✅ Compute Shader
端侧 ML 推理困难现实可行
浏览器支持全面⚠️ 主流浏览器已支持,但需确认目标用户环境

💡 对前端的意义:WebGPU 让端侧模型推理(配合 Wasm)成为现实, 是 AI 应用下沉到浏览器的重要前提(见 AI 领域文档)。


自检清单 ​

  • [ ] 能说出 Web Components 三块基石,以及它"适合/不适合"的场景
  • [ ] 能判断什么任务该用 WebAssembly(计算 > 边界开销)
  • [ ] 能说清 Web Worker 的三个限制,以及 Transferable 零拷贝的作用
  • [ ] 能解释 Service Worker 更新滞后与缓存脏数据两个坑
  • [ ] 能说出 WebRTC 为什么"P2P 但仍需服务器"(STUN/TURN/信令)

常见误区 ​

❌ 误区✅ 事实
"WebAssembly 会取代 JS"它是补充,DOM 操作仍要 JS 胶水层
"Worker 里能操作 DOM"不能,只能通过 postMessage 通信
"PWA = 加个 manifest"核心是 Service Worker,且更新与缓存策略最难
"WebRTC 不需要服务器"需要 STUN/TURN + 信令服务器

动手练习 ​

  1. 写一个 Worker,把 10 万条数据的排序挪进去,用 Performance 面板对比主线程前后的长任务时长。
  2. 用 Transferable 传一个 50MB 的 ArrayBuffer,验证零拷贝(对比普通 postMessage 的耗时)。
  3. 给本站(VitePress)加一个最简单的 Service Worker,体会"更新滞后"问题,再用 skipWaiting 修复。

相关文档 ​