前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
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 热点
旧版
首页程序员面试题库ArrayBuffer 与 SharedArrayBuffer 区别
JavaScript数据处理

ArrayBuffer 和 SharedArrayBuffer 有什么区别,分别用在什么场景?

ArrayBuffer 同一时刻只属于一个线程,发给 Worker 时要么复制一份,要么转移过去、自己这边就不能用了。SharedArrayBuffer 是多个线程同时读写同一块内存,不用复制,但并发修改会互相覆盖,所以要配合 Atomics 做原子操作。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#数据处理
先看核心答案读代码示例
理解线索

一块内存归谁

  1. ArrayBuffer只有一个主人,转移后原来的变成长度为 0 的空壳
  2. SharedArrayBuffer多个线程共用,谁写了别人都能看到
  3. Atomics把「读、改、写」变成不会被打断的一步,还能让线程等待和唤醒

SharedArrayBuffer 不能放进 postMessage 的转移列表,它的目的就是共享,传过去的是同一块内存的引用。

核心回答

先记住这个答案

ArrayBuffer 是一段固定长度的原始字节,同一时刻只属于一个线程。通过 postMessage 发给 Worker 时,默认会复制一份;放进转移列表的话,内存直接交给 Worker,发送方的 ArrayBuffer 长度变成 0,不能再用。SharedArrayBuffer 则是主线程和多个 Worker 共用同一块内存,一方写入另一方马上能读到,省去了复制。但并发读写会出现竞争,比如两个线程同时对一个计数器加 1,结果可能只加了一次,所以要用 Atomics 提供的原子操作。大文件交给一个 Worker 处理用 ArrayBuffer 转移就够了,多个线程需要持续共享状态时才用 SharedArrayBuffer。

  • ArrayBuffer 发给 Worker 只会复制或转移
  • SharedArrayBuffer 多个线程看到同一块内存
  • 共享不等于线程安全,value++ 不是原子的
  • 用 SharedArrayBuffer 要开启跨源隔离

用 Atomics 修改共享计数器

下面在同一个线程里用两个视图指向同一块共享内存,模拟两个线程各自持有一个视图的情况。

两个视图,同一块内存JavaScript
const shared = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT)  // 4 个字节
const firstView = new Int32Array(shared)
const secondView = new Int32Array(shared)

console.log(Atomics.add(firstView, 0, 2))   // 返回加之前的值
console.log(Atomics.add(secondView, 0, 3))
console.log(Atomics.load(firstView, 0))     // 两次加法都生效了
查看输出与解释
0
2
5

Atomics.add 返回的是修改前的值,所以依次输出 0 和 2。两个视图指向同一块内存,最后读出来是 5。真实场景里,firstView 在主线程,secondView 在 Worker 里,Worker 通过 postMessage 收到的 shared 就是同一块内存。

为什么共享内存需要原子操作

view[0]++ 看起来是一步,实际上是三步:读出当前值、加 1、写回去。两个线程同时执行时,可能都读到了 0,各自加 1 后都写回 1,结果少加了一次。这叫竞态条件。

Atomics 能做什么
Atomics.add、Atomics.sub、Atomics.compareExchange 这些方法把读改写合成一个不会被打断的操作,别的线程看不到中间状态。Atomics.wait 和 Atomics.notify 能让一个线程等待、另一个线程唤醒它,用来实现锁和信号。注意浏览器主线程不允许调用 Atomics.wait 阻塞,主线程里要等待的话,可以在支持的浏览器里用非阻塞的 Atomics.waitAsync。 大多数前端场景其实用不上这些。Worker 处理完把结果发回来,用 postMessage 传消息就够了,状态不共享也就没有竞争。

浏览器里的启用条件

SharedArrayBuffer 能配合 Worker 做出高精度计时器,可能被用来发起 Spectre 这类侧信道攻击。所以浏览器要求页面处于跨源隔离状态才开放它:响应头要带 Cross-Origin-Opener-Policy: same-origin 和 Cross-Origin-Embedder-Policy: require-corp。

检查是否可用
页面里可以读 crossOriginIsolated,为 true 才能正常使用 SharedArrayBuffer。开启 require-corp 后,页面加载的跨域图片、脚本都要带 CORS 或 Cross-Origin-Resource-Policy 响应头,否则会被拦截,接入第三方资源多的站点要先评估影响。
回答前,多想一步

容易答错的地方

以为 Atomics 只能用在 SharedArrayBuffer 上
Atomics.add、Atomics.load 这些方法在普通 ArrayBuffer 上的整数类型数组也能调用,只是单线程里没什么意义。真正要求共享内存的是 Atomics.wait,它只接受基于 SharedArrayBuffer 的 Int32Array 或 BigInt64Array。另外 Atomics 只支持整数类型数组,Float64Array 和 Uint8ClampedArray 都不行。
以为用了 SharedArrayBuffer 就是线程安全的
共享只是让多个线程看到同一块内存,普通读写之间依然会互相覆盖。需要并发修改的位置,都要用 Atomics 的方法,复杂的状态还要自己设计加锁的规则。
试着用自己的话回答

面试官还会怎么问?

什么时候优先用 ArrayBuffer 转移?

数据很大、交给一个 Worker 处理、主线程之后不再需要原数据时,比如把一段视频帧交给 Worker 解码。写成 worker.postMessage(buffer, [buffer]),内存直接移交,不需要复制,也不用处理同步问题。

转移之后原来的 ArrayBuffer 会怎样?

它会变成「已分离」状态,byteLength 变成 0,基于它创建的类型化数组长度也变成 0,读出来都是 undefined,调用 slice() 这类方法会抛 TypeError。

Node.js 里也有 SharedArrayBuffer 吗?

有,配合 worker_threads 使用,不需要浏览器那样的跨源隔离设置。

从一道题,走向一组知识

把知识连起来

数据处理

ArrayBuffer 的 transfer 和 slice 有什么区别,处理大数据时该用哪个?

ArrayBuffer 的转移不止 postMessage 一种,transfer() 方法能在同一个线程里完成所有权移交。

数据处理

怎么把 Blob 转成 ArrayBuffer,有哪些 API 可以用?

发给 Worker 处理的二进制数据,通常是先从 Blob 或文件读成 ArrayBuffer 得来的。

参考资料

  • JavaScript:数据处理参考资料
  • MDN:Atomics

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 用 Atomics 修改共享计数器
  3. 为什么共享内存需要原子操作
  4. 浏览器里的启用条件
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑