SharedArrayBuffer 与 Buffer
- 首先,需要明确的是,一个中文:大多数情况是占用3个字节。
const str = "你好,世界!";
const bufferStr = new TextEncoder().encode(str);
console.log(bufferStr / str.length);
Uint8Array 等 typed array
- Uint8Array 可以简单理解为数组,这个数组的每一项是 8 位,在计算机中占用 1 个字节。
const uint8 = new Uint8Array(10);
unit8[0] = 255;
unit8.set([1, 2, 3], 1);
console.log(uint8);
uint8[0] = 256;
console.log(uint8[0]);
- Uint32Array 就很好理解了,它的每一项是 32 位,在计算机中占用 4 个字节。
const uint32 = new Uint32Array(10);
uint32[0] = 4294967295;
console.log(uint32);
uint32[0] = 4294967296;
console.log(uint32[0]);
- Int32Array、Float32Array 等类型的数组也是类似的,只是每一项占用的字节数不同。
SharedArrayBuffer 与 typed array
- SharedArrayBuffer 就是一块共享内存区域,可以被多个线程访问和修改。
它本身并没有提供任何方法来操作数据,而是需要通过视图(如 Uint8Array)来访问和修改数据。
const sab = new SharedArrayBuffer(1024);
const uint8 = new Uint8Array(sab);
console.log(uint8.length);
- 对于多个 Uint8Array 操作同一块 SharedArrayBuffer 的情况,修改其中一个 Uint8Array 的数据会影响到其他
Uint8Array,因为它们共享同一块内存。
const sab = new SharedArrayBuffer(1024);
const uint8_1 = new Uint8Array(sab);
const uint8_2 = new Uint8Array(sab);
uint8_1[0] = 42;
console.log(uint8_2[0]);
TextEncoder 与 TextDecoder
- 看懂了上面的示例,这个就很好理解了。
在前面讲到,typed array 是用来操作二进制数据的,而 TextEncoder 和 TextDecoder 则是用来在字符串和二进制数据之间进行转换的工具。
但是 typed array 在定义是已经确定了,每一项需的大小是多少。以中文和 UInt8Array 为例:
每个中文占用 3 个字节,而 UInt8Array 的每一项只能存储 1 个字节,所以当我们将一个字符串转换为 Uint8Array 时,可能会出现数据丢失的情况。
const str = "你好,世界!";
const uint8 = new Uint8Array(str.length);
for (let i = 0; i < str.length; i++) {
uint8[i] = str.charCodeAt(i);
}
console.log(uint8);
const str = "你好,世界!";
const coderStr = new TextEncoder().encode(str);
const arrayBuffer = new Uint8Array(coderStr.byteLength);
arrayBuffer.set(coderStr);
console.log(new TextDecoder().decode(arrayBuffer));
- 扩展点:前面提到,Uint8Array 每一项是1个字节,也就是说,UintArray 的每一项最多不能超过 255,如果超过了就会发生溢出。
那么,TextEncoder 会不会输出超过 255 的值呢?答案是不会的。因为 TextEncoder 是以 utf-8 的方式编码字符串的,
而 utf-8 的编码规则是:对于 ASCII 字符(即 Unicode 码点在 U+0000 到 U+007F 之间的字符),使用一个字节进行编码;对于其他字符,使用多个字节进行编码。因此,TextEncoder 输出的值不会超过 255。
新的概念
- 掌握的上面的知识,就可以理解到,其实 SharedArrayBuffer 是可以被多种 byte array 操作的。如:一个 SharedArrayBuffer 可以被一个 Uint8Array 和一个 Uint32Array 等同时操作。
但是,要计算要其字节值,因为 Uint8Array 的每一项是 1 个字节,而 Uint32Array 的每一项是 4 个字节,所以当我们通过 Uint8Array 修改 SharedArrayBuffer 中的数据时,可能会影响到通过 Uint32Array 访问的数据,反之亦然。
const sab = new SharedArrayBuffer(1024);
const idView = new Int32Array(sab, 0, 1);
idView[0] = 999527;
const dataView = new Uint8Array(sab, 4);
dataView.set([0xff, 0xd8, 0xff]);
const sab = new SharedArrayBuffer(1024);
const idView = new Int32Array(sab, 0, 1);
const dataView = new Uint8Array(sab, 4);
dataView.set([0xff, 0xd8, 0xff]);
- 多 typed array 操作时,一定要计算好字节数,要不然会出现数据被覆盖的情况。