ArrayBuffer

ArrayBuffer

The ArrayBuffer object is used to represent a generic, fixed-length raw binary data buffer.

It is an array of bytes, often referred to in other languages as a “byte array”.You cannot directly manipulate the contents of an ArrayBuffer; instead, you create one of the typed array objects or a DataView object which represents the buffer in a specific format, and use that to read and write the contents of the buffer.

The ArrayBuffer() constructor creates a new ArrayBuffer of the given length in bytes. You can also get an array buffer from existing data, for example from a Base64 string or from a local file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Constructor
new ArrayBuffer(byteLength)

# Static properties
get ArrayBuffer[@@species]
# The constructor function that is used to create derived objects.

# Static methods
ArrayBuffer.isView(arg)
# Returns true if arg is one of the ArrayBuffer views, such as typed array objects or a DataView. Returns false otherwise.

# Instance properties
ArrayBuffer.prototype.byteLength
# The read-only size, in bytes, of the ArrayBuffer. This is established when the array is constructed and cannot be changed.

# Instance methods
ArrayBuffer.prototype.slice(begin[, end])
# Returns a new ArrayBuffer whose contents are a copy of this ArrayBuffer's bytes from begin (inclusive) up to end (exclusive). If either begin or end is negative, it refers to an index from the end of the array, as opposed to from the beginning.
# 允许将内存区域的一部分,拷贝生成一个新的ArrayBuffer对象
# 除了slice方法,ArrayBuffer对象不提供任何直接读写内存的方法,只允许在其上方建立视图,然后通过视图读写。

Creating an ArrayBuffer

1
2
const buffer = new ArrayBuffer(8);
const view = new Int32Array(buffer);

TypedArray

A TypedArray object describes an array-like view of an underlying binary data buffer. There is no global property named TypedArray, nor is there a directly visible TypedArray constructor. Instead, there are a number of different global properties, whose values are typed array constructors for specific element types, listed below. On the following pages you will find common properties and methods that can be used with any typed array containing elements of any type.

TypedArray objects

TypeValue RangeSize in bytesDescriptionWeb IDL typeEquivalent C type
Int8Array-128 to 12718-bit two’s complement signed integerbyteint8_t
Uint8Array0 to 25518-bit unsigned integeroctetuint8_t
Uint8ClampedArray0 to 25518-bit unsigned integer (clamped)octetuint8_t
Int16Array-32768 to 32767216-bit two’s complement signed integershortint16_t
Uint16Array0 to 65535216-bit unsigned integerunsigned shortuint16_t
Int32Array-2147483648 to 2147483647432-bit two’s complement signed integerlongint32_t
Uint32Array0 to 4294967295432-bit unsigned integerunsigned longuint32_t
Float32Array1.2×10-38 to 3.4×1038432-bit IEEE floating point number (7 significant digits e.g., 1.234567)unrestricted floatfloat
Float64Array5.0×10-324 to 1.8×10308864-bit IEEE floating point number (16 significant digits e.g., 1.23456789012345)unrestricted doubledouble
BigInt64Array-263 to 263-1864-bit two’s complement signed integerbigintint64_t (signed long long)
BigUint64Array0 to 264-1864-bit unsigned integerbigintuint64_t (unsigned long long)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# Constructor
# This object cannot be instantiated directly. Instead, you create an instance of an array of a particular type, such as a Int8Array or a BigInt64Array. These objects all have a common syntax for their constructors:
new TypedArray();
new TypedArray(length);
new TypedArray(typedArray);
new TypedArray(object); // object = TypedArray.from()
new TypedArray(buffer [, byteOffset [, length]]);

# Static properties
TypedArray.BYTES_PER_ELEMENT
# Returns a number value of the element size for the different TypedArray objects.

TypedArray.name
# Returns the string value of the constructor name (e.g, "Int8Array").

get TypedArray[@@species]
# The constructor function used to create derived objects.

TypedArray.prototype
# Prototype for TypedArray objects.

# Static methods
TypedArray.from()
# Creates a new TypedArray from an array-like or iterable object. See also Array.from().

TypedArray.of()
# Creates a new TypedArray with a variable number of arguments. See also Array.of().

# Instance properties
TypedArray.prototype.buffer
# Returns the ArrayBuffer referenced by the typed array. Fixed at construction time and thus read only.

TypedArray.prototype.byteLength
# Returns the length (in bytes) of the typed array. Fixed at construction time and thus read only.

TypedArray.prototype.byteOffset
# Returns the offset (in bytes) of the typed array from the start of its ArrayBuffer. Fixed at construction time and thus read only.

TypedArray.prototype.length
# Returns the number of elements held in the typed array. Fixed at construction time and thus read only.

# Instance methods
TypedArray.prototype.copyWithin()
# Copies a sequence of array elements within the array. See also Array.prototype.copyWithin().

TypedArray.prototype.entries()
# Returns a new array iterator object that contains the key/value pairs for each index in the array. See also Array.prototype.entries().

TypedArray.prototype.every()
# Tests whether all elements in the array pass the test provided by a function. See also Array.prototype.every().

TypedArray.prototype.fill()
# Fills all the elements of an array from a start index to an end index with a static value. See also Array.prototype.fill().

TypedArray.prototype.filter()
# Creates a new array with all of the elements of this array for which the provided filtering function returns true. See also Array.prototype.filter().

TypedArray.prototype.find()
# Returns the found value in the array, if an element in the array satisfies the provided testing function, or undefined if not found. See also Array.prototype.find().

TypedArray.prototype.findIndex()
# Returns the found index in the array, if an element in the array satisfies the provided testing function or -1 if not found. See also Array.prototype.findIndex().

TypedArray.prototype.forEach()
# Calls a function for each element in the array. See also Array.prototype.forEach().

TypedArray.prototype.includes()
# Determines whether a typed array includes a certain element, returning true or false as appropriate. See also Array.prototype.includes().

TypedArray.prototype.indexOf()
# Returns the first (least) index of an element within the array equal to the specified value, or -1 if none is found. See also Array.prototype.indexOf().

TypedArray.prototype.join()
# Joins all elements of an array into a string. See also Array.prototype.join().

TypedArray.prototype.keys()
# Returns a new array iterator that contains the keys for each index in the array. See also Array.prototype.keys().

TypedArray.prototype.lastIndexOf()
# Returns the last (greatest) index of an element within the array equal to the specified value, or -1 if none is found. See also Array.prototype.lastIndexOf().

TypedArray.prototype.map()
# Creates a new array with the results of calling a provided function on every element in this array. See also Array.prototype.map().

TypedArray.prototype.reduce()
# Apply a function against an accumulator and each value of the array (from left-to-right) as to reduce it to a single value. See also Array.prototype.reduce().

TypedArray.prototype.reduceRight()
# Apply a function against an accumulator and each value of the array (from right-to-left) as to reduce it to a single value. See also Array.prototype.reduceRight().

TypedArray.prototype.reverse()
# Reverses the order of the elements of an array — the first becomes the last, and the last becomes the first. See also Array.prototype.reverse().

TypedArray.prototype.set()
# Stores multiple values in the typed array, reading input values from a specified array.

TypedArray.prototype.slice()
# Extracts a section of an array and returns a new array. See also Array.prototype.slice().

TypedArray.prototype.some()
# Returns true if at least one element in this array satisfies the provided testing function. See also Array.prototype.some().

TypedArray.prototype.sort()
# Sorts the elements of an array in place and returns the array. See also Array.prototype.sort().

TypedArray.prototype.subarray()
# Returns a new TypedArray from the given start and end element index.

TypedArray.prototype.values()
# Returns a new array iterator object that contains the values for each index in the array. See also Array.prototype.values().

TypedArray.prototype.toLocaleString()
# Returns a localized string representing the array and its elements. See also Array.prototype.toLocaleString().

TypedArray.prototype.toString()
# Returns a string representing the array and its elements. See also Array.prototype.toString().

TypedArray.prototype[@@iterator]()
# Returns a new array iterator object that contains the values for each index in the array.

TypedArray 数组没有concat方法。如果想要合并多个 TypedArray 数组,可以用下面这个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function concatenate(resultConstructor, ...arrays) {
let totalLength = 0;
for (let arr of arrays) {
totalLength += arr.length;
}
let result = new resultConstructor(totalLength);
let offset = 0;
for (let arr of arrays) {
result.set(arr, offset);
offset += arr.length;
}
return result;
}

concatenate(Uint8Array, Uint8Array.of(1, 2), Uint8Array.of(3, 4))
// Uint8Array [1, 2, 3, 4]

// TypedArray 数组与普通数组一样,部署了 Iterator 接口,所以可以被遍历。
let ui8 = Uint8Array.of(0, 1, 2);
for (let byte of ui8) {
console.log(byte);
}
// 0
// 1
// 2

Property access

You can reference elements in the array using standard array index syntax (that is, using bracket notation). However, getting or setting indexed properties on typed arrays will not search in the prototype chain for this property, even when the indices are out of bound. Indexed properties will consult the ArrayBuffer and will never look at object properties. You can still use named properties, just like with all objects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var dv = new Int8Array([1, 2, 3]);

// Setting and getting using standard array syntax
var int16 = new Int16Array(2);
int16[0] = 42;
console.log(int16[0]); // 42

// Indexed properties on prototypes are not consulted (Fx 25)
Int8Array.prototype[20] = 'foo';
(new Int8Array(32))[20]; // 0
// even when out of bound
Int8Array.prototype[20] = 'foo';
(new Int8Array(8))[20]; // undefined
// or with negative integers
Int8Array.prototype[-1] = 'foo';
(new Int8Array(8))[-1]; // undefined

// Named properties are allowed, though (Fx 30)
Int8Array.prototype.foo = 'bar';
(new Int8Array(32)).foo; // "bar"

DataView

The DataView view provides a low-level interface for reading and writing multiple number types in a binary ArrayBuffer, without having to care about the platform’s endianness.

Multi-byte number formats are represented in memory differently depending on machine architecture — see Endianness for an explanation. DataView accessors provide explicit control of how data is accessed, regardless of the executing computer’s endianness.

Because JavaScript does not currently include standard support for 64-bit integer values, DataView does not offer native 64-bit operations. As a workaround, you could implement your own getUint64() function to obtain a value with precision up to Number.MAX_SAFE_INTEGER, which could suffice for certain cases.

1
2
3
4
5
6
7
8
9
10
11
12
13
function getUint64(dataview, byteOffset, littleEndian) {
// split 64-bit number into two 32-bit (4-byte) parts
const left = dataview.getUint32(byteOffset, littleEndian);
const right = dataview.getUint32(byteOffset+4, littleEndian);

// combine the two 32-bit values
const combined = littleEndian? left + 2**32*right : 2**32*left + right;

if (!Number.isSafeInteger(combined))
console.warn(combined, 'exceeds MAX_SAFE_INTEGER. Precision may be lost');

return combined;
}

Alternatively, if you need full 64-bit range, you can create a BigInt. Further, although native BigInts are much faster than user-land library equivalents, BigInts will always be much slower than 32-bit integers in JavaScript due to the nature of their variable size.

1
2
3
4
5
6
7
8
9
const BigInt = window.BigInt, bigThirtyTwo = BigInt(32), bigZero = BigInt(0);
function getUint64BigInt(dataview, byteOffset, littleEndian) {
// split 64-bit number into two 32-bit (4-byte) parts
const left = BigInt(dataview.getUint32(byteOffset|0, !!littleEndian)>>>0);
const right = BigInt(dataview.getUint32((byteOffset|0) + 4|0, !!littleEndian)>>>0);

// combine the two 32-bit values and return
return littleEndian ? (right<<bigThirtyTwo)|left : (left<<bigThirtyTwo)|right;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# Constructor
DataView()
# Creates a new DataView object.

# Instance properties
DataView.prototype.buffer
# The ArrayBuffer referenced by this view. Fixed at construction time and thus read only.

DataView.prototype.byteLength
# The length (in bytes) of this view from the start of its ArrayBuffer. Fixed at construction time and thus read only.

DataView.prototype.byteOffset
# The offset (in bytes) of this view from the start of its ArrayBuffer. Fixed at construction time and thus read only.

# Instance methods
DataView.prototype.getInt8()
# Gets a signed 8-bit integer (byte) at the specified byte offset from the start of the view.

DataView.prototype.getUint8()
# Gets an unsigned 8-bit integer (unsigned byte) at the specified byte offset from the start of the view.

DataView.prototype.getInt16()
# Gets a signed 16-bit integer (short) at the specified byte offset from the start of the view.

DataView.prototype.getUint16()
# Gets an unsigned 16-bit integer (unsigned short) at the specified byte offset from the start of the view.

DataView.prototype.getInt32()
# Gets a signed 32-bit integer (long) at the specified byte offset from the start of the view.

DataView.prototype.getUint32()
# Gets an unsigned 32-bit integer (unsigned long) at the specified byte offset from the start of the view.

DataView.prototype.getFloat32()
# Gets a signed 32-bit float (float) at the specified byte offset from the start of the view.

DataView.prototype.getFloat64()
# Gets a signed 64-bit float (double) at the specified byte offset from the start of the view.

DataView.prototype.getBigInt64()
# Gets a signed 64-bit integer (long long) at the specified byte offset from the start of the view.

DataView.prototype.getBigUint64()
# Gets an unsigned 64-bit integer (unsigned long long) at the specified byte offset from the start of the view.

DataView.prototype.setInt8()
# Stores a signed 8-bit integer (byte) value at the specified byte offset from the start of the view.

DataView.prototype.setUint8()
# Stores an unsigned 8-bit integer (unsigned byte) value at the specified byte offset from the start of the view.

DataView.prototype.setInt16()
# Stores a signed 16-bit integer (short) value at the specified byte offset from the start of the view.

DataView.prototype.setUint16()
# Stores an unsigned 16-bit integer (unsigned short) value at the specified byte offset from the start of the view.

DataView.prototype.setInt32()
# Stores a signed 32-bit integer (long) value at the specified byte offset from the start of the view.

DataView.prototype.setUint32()
# Stores an unsigned 32-bit integer (unsigned long) value at the specified byte offset from the start of the view.

DataView.prototype.setFloat32()
# Stores a signed 32-bit float (float) value at the specified byte offset from the start of the view.

DataView.prototype.setFloat64()
# Stores a signed 64-bit float (double) value at the specified byte offset from the start of the view.

DataView.prototype.setBigInt64()
# Stores a signed 64-bit integer (long long) value at the specified byte offset from the start of the view.

DataView.prototype.setBigUint64()
# Stores an unsigned 64-bit integer (unsigned long long) value at the specified byte offset from the start of the view.

Example

1
2
3
4
5
var buffer = new ArrayBuffer(16);
var view = new DataView(buffer, 0);

view.setInt16(1, 42);
view.getInt16(1); // 42

Receiving binary data using JavaScript typed arrays

The responseType property of the XMLHttpRequest object can be set to change the expected response type from the server. Possible values are the empty string (default), "arraybuffer", "blob", "document", "json", and "text". The response property will contain the entity body according to responseType, as an ArrayBuffer, Blob, Document, JSON, or string. This is null if the request is not complete or was not successful.

This example reads an image as a binary file and creates an 8-bit unsigned integer array from the raw bytes. Note that this will not decode the image and read the pixels. You will need a png decoding library for that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "arraybuffer";

oReq.onload = function (oEvent) {
var arrayBuffer = oReq.response; // Note: not oReq.responseText
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
for (var i = 0; i < byteArray.byteLength; i++) {
// do something with each byte in the array
}
}
};

oReq.send(null);
1
2
3
4
5
6
7
8
9
10
var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "blob";

oReq.onload = function(oEvent) {
var blob = oReq.response;
// ...
};

oReq.send();

Receiving binary data in older browsers

1
2
3
4
5
6
7
8
9
10
11
12
function load_binary_resource(url) {
var req = new XMLHttpRequest();
req.open('GET', url, false);
//XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com]
req.overrideMimeType('text\/plain; charset=x-user-defined');
req.send(null);
if (req.status != 200) return '';
return req.responseText;
}

var filestream = load_binary_resource(url);
var abyte = filestream.charCodeAt(x) & 0xff; // throw away high-order byte (f7)

Sending binary data

The send method of the XMLHttpRequest has been extended to enable easy transmission of binary data by accepting an ArrayBuffer, Blob, or File object.

The following example creates a text file on-the-fly and uses the POST method to send the “file” to the server. This example uses plain text, but you can imagine the data being a binary file instead.

1
2
3
4
5
6
7
8
9
var oReq = new XMLHttpRequest();
oReq.open("POST", url, true);
oReq.onload = function (oEvent) {
// Uploaded.
};

var blob = new Blob(['abc123'], {type: 'text/plain'});

oReq.send(blob);

Sending typed arrays as binary data

1
2
3
4
5
6
7
8
9
10
11
var myArray = new ArrayBuffer(512);
var longInt8View = new Uint8Array(myArray);

// generate some data
for (var i=0; i< longInt8View.length; i++) {
longInt8View[i] = i % 256;
}

var xhr = new XMLHttpRequest;
xhr.open("POST", url, false);
xhr.send(myArray);
Reference
  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
  3. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView
  4. https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data