谈谈es6的ArrayBuffer 对象

写在前面

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

以下是一个简单的示例,展示如何创建一个 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 方法,这个操作是原子的,因此不会出现数据竞争问题。

相关推荐
小伟童鞋4 分钟前
c++中导出函数调用约定为__stdcall类型函数并指定导出函数名称
开发语言·c++
维C泡泡5 分钟前
C++初认、命名规则、输入输出、函数重载、引用+coust引用
开发语言·c++
a73601510 分钟前
二十二、包管理与发布 (Cargo 进阶)
开发语言·rust
郝学胜-神的一滴1 小时前
深入探索 C++ 元组:从基础到高级应用
开发语言·c++·stl·软件工程
I'm a winner1 小时前
第七章:AI进阶之------输入与输出函数(一)
开发语言·人工智能·python·深度学习·神经网络·microsoft·机器学习
木心操作1 小时前
js生成excel表格进阶版
开发语言·javascript·ecmascript
听情歌落俗1 小时前
MATLAB3-1变量-台大郭彦甫
开发语言·笔记·算法·matlab·矩阵
zhangfeng11332 小时前
在 R 语言里,`$` 只有一个作用 按名字提取“列表型”对象里的单个元素 对象 $ 名字
开发语言·windows·r语言
文弱书生6562 小时前
5.后台运行设置和包设计与实现
服务器·开发语言·c#
编码浪子2 小时前
趣味学RUST基础篇(异步补充)
开发语言·后端·rust