谈谈es6的ArrayBuffer 对象

写在前面

ArrayBuffer 是一种固定长度的二进制数据缓冲区。它可以用来在 JavaScript 中存储和操作大量的二进制数据。ArrayBuffer 本身不提供直接访问其内容的方法,而是通过其他对象(如 TypedArray 和 DataView)来读取和写入数据。

以下是一个简单的示例,展示如何创建一个 ArrayBuffer 对象并填充它:

javascript 复制代码
const buffer = new ArrayBuffer(16); // 创建一个 16 字节的 ArrayBuffer
const view = new Uint8Array(buffer); // 创建一个 Uint8Array 视图

for (let i = 0; i < buffer.byteLength; i++) {
  view[i] = i * 2; // 填充数据
}

console.log(view); // [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]

TypedArray 视图

TypedArray 是一种允许你在 ArrayBuffer 上创建不同类型的数组视图的对象。这些视图提供了对 ArrayBuffer 中数据的直接访问,并且可以以不同的方式解释数据(例如,作为无符号整数、有符号整数、浮点数等)。

以下是一些常见的 TypedArray 视图:

  • Int8Array: 有符号 8 位整数
  • Uint8Array: 无符号 8 位整数
  • Int16Array: 有符号 16 位整数
  • Uint16Array: 无符号 16 位整数
  • Int32Array: 有符号 32 位整数
  • Uint32Array: 无符号 32 位整数
  • Float32Array: 32 位浮点数
  • Float64Array: 64 位浮点数

以下是一个示例,展示如何使用 TypedArray 视图来读取和写入 ArrayBuffer 中的数据:

javascript 复制代码
const buffer = new ArrayBuffer(16);
const int16View = new Int16Array(buffer);

int16View[0] = 1;
int16View[1] = 2;

console.log(int16View); // [1, 2, 0, 0, 0, 0, 0, 0]

复合视图

复合视图是指在同一个 ArrayBuffer 上创建多个不同类型的 TypedArray 视图。这样可以方便地在同一块内存中存储和操作不同类型的数据。

以下是一个示例,展示如何在同一个 ArrayBuffer 上创建多个不同类型的视图:

javascript 复制代码
const buffer = new ArrayBuffer(24);
const uint8View = new Uint8Array(buffer);
const uint16View = new Uint16Array(buffer);
const float32View = new Float32Array(buffer);

uint8View[0] = 1;
uint8View[1] = 2;
uint8View[2] = 3;
uint8View[3] = 4;

console.log(uint16View); // [258, 771, 0, 0]
console.log(float32View); // [1.401298464324817e-45, 5.605193857299227e-45, 0, 0]

DataView 视图

DataView 是一种更灵活的视图,可以在 ArrayBuffer 上读取和写入不同类型的数据,而不需要创建多个 TypedArray 视图。它提供了一组方法来读取和写入各种类型的数据,包括整数、浮点数和字符串。

以下是一个示例,展示如何使用 DataView 视图来读取和写入 ArrayBuffer 中的数据:

javascript 复制代码
const buffer = new ArrayBuffer(16);
const dataView = new DataView(buffer);

dataView.setInt16(0, 1);
dataView.setFloat32(4, 3.14);

console.log(dataView.getInt16(0)); // 1
console.log(dataView.getFloat32(4)); // 3.14

二进制数组的应用

二进制数组在许多领域都有广泛的应用,例如:

  • 图像和视频处理:可以使用二进制数组来存储和操作图像和视频数据。
  • 网络通信:可以使用二进制数组来发送和接收二进制数据。
  • 加密和解密:可以使用二进制数组来存储和操作加密和解密的数据。
  • 游戏开发:可以使用二进制数组来存储和操作游戏中的数据。

以下是一个简单的示例,展示如何使用二进制数组来读取和显示一张 PNG 图像:

javascript 复制代码
const img = document.createElement('img');
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

fetch('image.png')
 .then(response => response.arrayBuffer())
 .then(buffer => {
    const uint8View = new Uint8Array(buffer);
    const pngData = uint8View.slice(0, 8); // PNG 文件头

    if (pngData[0] === 137 && pngData[1] === 80 && pngData[2] === 78 && pngData[3] === 71 && pngData[4] === 13 && pngData[5] === 10 && pngData[6] === 26 && pngData[7] === 10) {
      const pngDecoder = new PNGDecoder();
      const decodedData = pngDecoder.decode(buffer);

      canvas.width = decodedData.width;
      canvas.height = decodedData.height;
      ctx.putImageData(decodedData, 0, 0);
      img.src = canvas.toDataURL();
      document.body.appendChild(img);
    } else {
      console.error('Invalid PNG file');
    }
  });

SharedArrayBuffer

SharedArrayBuffer 是一种允许多个线程或 Web Worker 共享同一块内存的对象。它可以用来实现高效的并行计算和数据共享。

以下是一个简单的示例,展示如何使用 SharedArrayBuffer 在主线程和 Web Worker 之间共享数据:

javascript 复制代码
// 主线程
const buffer = new SharedArrayBuffer(4);
const uint8View = new Uint8Array(buffer);

const worker = new Worker('worker.js');
worker.postMessage({ buffer });

// worker.js
self.onmessage = function(event) {
  const buffer = event.data.buffer;
  const uint8View = new Uint8Array(buffer);

  // 在 worker 中修改数据
  uint8View[0] = 1;
  uint8View[1] = 2;
  uint8View[2] = 3;
  uint8View[3] = 4;
};

Atomics 对象

Atomics 是一个全局对象,提供了一组方法来执行原子操作(即不可分割的操作)在 SharedArrayBuffer 上。这些方法可以用来实现线程安全的并发操作。

以下是一个简单的示例,展示如何使用 Atomics 对象来实现一个线程安全的计数器:

javascript 复制代码
// 主线程
const buffer = new SharedArrayBuffer(4);
const uint32View = new Uint32Array(buffer);

const worker1 = new Worker('worker1.js');
const worker2 = new Worker('worker2.js');

worker1.postMessage({ buffer });
worker2.postMessage({ buffer });

// worker1.js 和 worker2.js
self.onmessage = function(event) {
  const buffer = event.data.buffer;
  const uint32View = new Uint32Array(buffer);

  for (let i = 0; i < 1000000; i++) {
    Atomics.add(uint32View, 0, 1);
  }
};

在这个示例中,两个 Web Worker 都在尝试增加同一个计数器的值。由于使用了 Atomics.add 方法,这个操作是原子的,因此不会出现数据竞争问题。

相关推荐
Elastic 中国社区官方博客10 分钟前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
tyn18823 分钟前
记录本地安装nacos服务的方法及异常
java·开发语言
步行cgn1 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
传奇开心果编程2 小时前
【Rust入门练中学】第5课:引用与借用
开发语言·rust·引用·编程语言理论·通用编程语言·借用
qetfw2 小时前
Bash 变量:export、位置参数与默认值展开验证
linux·开发语言·chrome·bash
电子云与长程纠缠2 小时前
UE5魂系游戏开发教程05
开发语言·学习·游戏·ui·ue5
cspttty2 小时前
2027风险管理岗准备路线:数学与应用数学如何补齐金融、SQL与Python
开发语言·python·金融
我命由我123452 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
严谨的麻辣烫3 小时前
Python HTTP 连接池怎么用?从连接复用到请求异常排查
开发语言·python·http·requests·网络排查
码林鼠3 小时前
flutter状态管理入门教程-Riverpod
开发语言·javascript·flutter