型付き配列 - ブラウザのバイナリデータ

Ilmari Heikkinen

はじめに

型付き配列はブラウザに比較的最近追加されたもので、WebGL でバイナリデータを効率的に処理する必要性から生まれました。型付き配列は、C での配列の仕組みと同じように、型付きビューを含むメモリのスラブです。型付き配列は未加工のメモリを基盤としているため、JavaScript エンジンはデータをネイティブ表現に苦労して変換することなく、メモリをネイティブ ライブラリに直接渡すことができます。そのため、WebGL やバイナリデータを扱う他の API にデータを渡す場合、型付き配列は JavaScript 配列よりもはるかに優れたパフォーマンスを発揮します。

型付き配列ビューは、ArrayBuffer のセグメントに対する単一型配列のように機能します。通常の数値型はすべて、Float32Array、Float64Array、Int32Array、Uint8Array などの自己記述型の名前を持つビューがあります。また、Canvas の ImageData のピクセル配列型に代わる特別なビューである Uint8ClampedArray もあります。

DataView は 2 つ目のタイプのビューで、異種混合のデータを処理するためのものです。DataView オブジェクトには、配列のような API を使用する代わりに、任意のバイト オフセットで任意のデータ型を読み書きするための get/set API が用意されています。DataView は、ファイル ヘッダーなどの構造体のようなデータの読み取りと書き込みに最適です。

型付き配列の基本的な使い方

型付き配列ビュー

型付き配列を使用するには、ArrayBuffer とそのビューを作成する必要があります。最も簡単な方法は、目的のサイズと型の型付き配列ビューを作成することです。

// Typed array views work pretty much like normal arrays.
var f64a = new Float64Array(8);
f64a[0] = 10;
f64a[1] = 20;
f64a[2] = f64a[0] + f64a[1];

型付き配列ビューには、いくつかの種類があります。どれも同じ API を共有しているため、使い方をわかれば、使い方はほぼわかります。次の例で、現在存在する配列ビューを 1 つずつ作成します。

// Floating point arrays.
var f64 = new Float64Array(8);
var f32 = new Float32Array(16);

// Signed integer arrays.
var i32 = new Int32Array(16);
var i16 = new Int16Array(32);
var i8 = new Int8Array(64);

// Unsigned integer arrays.
var u32 = new Uint32Array(16);
var u16 = new Uint16Array(32);
var u8 = new Uint8Array(64);
var pixels = new Uint8ClampedArray(64);

3 行目は少し特殊で、入力値を 0 ~ 255 の間に収めます。これは、Canvas 画像処理アルゴリズムでは特に便利です。これにより、8 ビット範囲のオーバーフローを避けるために、画像処理計算を手動でクランプする必要がなくなりました。

たとえば、Uint8Array に保存された画像にガンマ係数を適用する方法を以下に示します。あまり美しくない:

u8[i] = Math.min(255, Math.max(0, u8[i] * gamma));

Uint8ClampedArray を使用すると、手動クランプをスキップできます。

pixels[i] *= gamma;

型付き配列ビューを作成するもう 1 つの方法は、まず ArrayBuffer を作成し、それを参照するビューを作成することです。外部データを取得する API は通常 ArrayBuffers で処理するため、この方法で型付き配列ビューを取得できます。

var ab = new ArrayBuffer(256); // 256-byte ArrayBuffer.
var faFull = new Uint8Array(ab);
var faFirstHalf = new Uint8Array(ab, 0, 128);
var faThirdQuarter = new Uint8Array(ab, 128, 64);
var faRest = new Uint8Array(ab, 192);

また、同じ ArrayBuffer に複数のビューを設定することもできます。

var fa = new Float32Array(64);
var ba = new Uint8Array(fa.buffer, 0, Float32Array.BYTES_PER_ELEMENT); // First float of fa.

型付き配列を別の型付き配列にコピーするには、型付き配列セット メソッドを使用するのが最も早い方法です。memcpy のような使用には、ビューのバッファに Uint8Array を作成し、set を使用してデータをコピーします。

function memcpy(dst, dstOffset, src, srcOffset, length) {
  var dstU8 = new Uint8Array(dst, dstOffset, length);
  var srcU8 = new Uint8Array(src, srcOffset, length);
  dstU8.set(srcU8);
};

DataView

異種の型のデータを含む ArrayBuffers を使用するには、バッファに対して DataView を使用するのが最も簡単な方法です。8 ビットの符号なし int のヘッダーの後に 2 つの 16 ビット int が続き、その後に 32 ビット浮動小数点数のペイロード配列が続くファイル形式があるとします。型付き配列ビューでこれを読み返すことは可能ですが、少し厄介です。DataView を使用すると、ヘッダーを読み取り、float 配列に型付き配列ビューを使用できます。

var dv = new DataView(buffer);
var vector_length = dv.getUint8(0);
var width = dv.getUint16(1); // 0+uint8 = 1 bytes offset
var height = dv.getUint16(3); // 0+uint8+uint16 = 3 bytes offset
var vectors = new Float32Array(width*height*vector_length);
for (var i=0, off=5; i<vectors.length; i++, off+=4) {
  vectors[i] = dv.getFloat32(off);
}

上記の例では、読み取った値はすべてビッグ エンディアンです。バッファ内の値がリトル エンディアンの場合は、オプションの littleEndian パラメータをゲッターに渡すことができます。

...
var width = dv.getUint16(1, true);
var height = dv.getUint16(3, true);
...
vectors[i] = dv.getFloat32(off, true);
...

なお、型付き配列ビューは常にネイティブのバイトオーダーになります。これは高速化が目的です。エンディアンが問題になるデータの読み取りと書き込みには、DataView を使用する必要があります。

DataView には、バッファに値を書き込むためのメソッドもあります。これらのセッターにはゲッターと同じ方法で名前が付けられ、「set」の後にデータ型が続きます。

dv.setInt32(0, 25, false); // set big-endian int32 at byte offset 0 to 25
dv.setInt32(4, 25); // set big-endian int32 at byte offset 4 to 25
dv.setFloat32(8, 2.5, true); // set little-endian float32 at byte offset 8 to 2.5

エンディアンに関する考察

エンディアン、つまりバイトオーダーとは、マルチバイトの数値がコンピュータのメモリに保存される順序です。ビッグ エンディアンという用語は、最上位バイトを最初に格納し、リトル エンディアンが最下位バイトを先頭に格納する CPU アーキテクチャを表します。特定の CPU アーキテクチャで使用するエンディアンは完全に任意です。どちらかを選ぶのに十分な理由があります。実際、一部の CPU は、ビッグ エンディアンとリトル エンディアンの両方のデータをサポートするように構成できます。

エンディアンについて考慮する必要がある理由理由は単純です。ディスクまたはネットワークからデータを読み書きする際は、データのエンディアンを指定する必要があります。これにより、データを処理する CPU のエンディアンに関係なく、データが正しく解釈されるようになります。昨今のネットワーク化が進む世界では、ビッグ エンディアンかリトル エンディアンかにかかわらず、あらゆる種類のデバイスを適切にサポートすることが不可欠です。デバイスはネットワーク上のサーバーや他のピアから送られるバイナリデータを処理する必要があるかもしれません。

DataView インターフェースは、ファイルやネットワークとの間でデータを読み書きするために特別に設計されています。DataView は、指定されたエンディアンを持つデータを操作します。エンディアンは大小にかかわらず、すべての値にアクセスするたびに指定する必要があります。これにより、バイナリデータを読み書きするときに、ブラウザが実行されている CPU のエンディアンに関係なく、一貫性のある正確な結果を得ることができます。

通常、アプリケーションがサーバーからバイナリデータを読み取る場合は、データを 1 回スキャンして、アプリケーションが内部で使用するデータ構造に変換する必要があります。このフェーズでは DataView を使用する必要があります。XMLHttpRequest、FileReader、その他の入出力 API で取得されたデータを直接マルチバイトの型付き配列ビュー(Int16Array、Uint16Array など)で使用することはおすすめしません。型付き配列ビューは CPU のネイティブ エンディアンを使用するためです。詳しくは後で説明します。

簡単な例をいくつか見てみましょう。Windows BMP ファイル形式は、Windows の初期において、画像を保存するための標準形式でした。上記のリンク先のドキュメントでは、ファイル内のすべての整数値がリトル エンディアン形式で格納されることが明記されています。この記事に付属する DataStream.js ライブラリを使用して BMP ヘッダーの先頭を解析するコード スニペットを以下に示します。

function parseBMP(arrayBuffer) {
  var stream = new DataStream(arrayBuffer, 0,
    DataStream.LITTLE_ENDIAN);
  var header = stream.readUint8Array(2);
  var fileSize = stream.readUint32();
  // Skip the next two 16-bit integers
  stream.readUint16();
  stream.readUint16();
  var pixelOffset = stream.readUint32();
  // Now parse the DIB header
  var dibHeaderSize = stream.readUint32();
  var imageWidth = stream.readInt32();
  var imageHeight = stream.readInt32();
  // ...
}

もう一つの例は、WebGL サンプル プロジェクトハイ ダイナミック レンジ レンダリングのデモで紹介したものです。このデモでは、ハイ ダイナミック レンジのテクスチャを表すリトル エンディアンの未加工の浮動小数点データをダウンロードし、WebGL にアップロードする必要があります。すべての CPU アーキテクチャで浮動小数点値を適切に解釈するコード スニペットを以下に示します。変数「arrayBuffer」が、XMLHttpRequest を介してサーバーからダウンロードしたばかりの ArrayBuffer であるとします。

var arrayBuffer = ...;
var data = new DataView(arrayBuffer);
var tempArray = new Float32Array(
  data.byteLength / Float32Array.BYTES_PER_ELEMENT);
var len = tempArray.length;
// Incoming data is raw floating point values
// with little-endian byte ordering.
for (var jj = 0; jj < len; ++jj) {
  tempArray[jj] =
    data.getFloat32(jj * Float32Array.BYTES_PER_ELEMENT, true);
}
gl.texImage2D(...other arguments...,
  gl.RGB, gl.FLOAT, tempArray);

経験則として、ウェブサーバーからバイナリデータを受け取ったら、DataView で 1 回のパスを実行します。個々の数値を読み取り、JavaScript オブジェクト(構造化データが少量の場合)または型付き配列ビュー(データ ブロックが大きい場合)など、他のデータ構造に保存します。これにより、コードがあらゆる種類の CPU で正しく動作するようになります。また、DataView を使用してファイルやネットワークにデータを書き込んでください。作成または使用するファイル形式を生成するには、さまざまな set メソッドに littleEndian 引数を適切に指定します。

ネットワークを経由するすべてのデータには、暗黙的に形式とエンディアンがあることに注意してください(少なくともマルチバイト値の場合は)。アプリケーションがネットワーク経由で送信するすべてのデータの形式を明確に定義し、文書化してください。

型付き配列を使用するブラウザ API

ここでは、現在型付き配列を使用しているさまざまなブラウザ API について簡単に説明します。現在、WebGL、Canvas、Web Audio API、XMLHttpRequests、WebSockets、Web Workers、Media Source API、File API などのクロップがあります。API のリストを見ると、型付き配列はパフォーマンス重視のマルチメディア作業や、効率的な方法でのデータの受け渡しに適していることがわかります。

WebGL

型配列の最初の使用は WebGL で行われ、バッファデータと画像データを渡すために使用されました。WebGL バッファ オブジェクトのコンテンツを設定するには、gl.bufferData() 呼び出しを型付き配列とともに使用します。

var floatArray = new Float32Array([1,2,3,4,5,6,7,8]);
gl.bufferData(gl.ARRAY_BUFFER, floatArray);

型付き配列は、テクスチャ データの受け渡しにも使用されます。型付き配列を使用してテクスチャ コンテンツを渡す基本的な例を次に示します。

var pixels = new Uint8Array(16*16*4); // 16x16 RGBA image
gl.texImage2D(
  gl.TEXTURE_2D, // target
  0, // mip level
  gl.RGBA, // internal format
  16, 16, // width and height
  0, // border
  gl.RGBA, //format
  gl.UNSIGNED_BYTE, // type
  pixels // texture data
);

また、WebGL コンテキストからピクセルを読み取るには、型付き配列が必要です。

var pixels = new Uint8Array(320*240*4); // 320x240 RGBA image
gl.readPixels(0, 0, 320, 240, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

描画キャンバス 2D

最近、Canvas ImageData オブジェクトが型付き配列の仕様に対応するように作成されました。これで、キャンバス要素上のピクセルの型付き配列表現を取得できるようになりました。これにより、キャンバスの要素を操作することなく、キャンバスのピクセル配列を作成、編集できるようになりました。

var imageData = ctx.getImageData(0,0, 200, 100);
var typedArray = imageData.data // data is a Uint8ClampedArray

XMLHttpRequest2

XMLHttpRequest が型指定配列ブーストにより、JavaScript 文字列を型付き配列に解析する必要がなくなり、型指定配列レスポンスを受け取れるようになりました。これは、取得したデータをマルチメディア API に直接渡す場合や、ネットワークから取得されたバイナリ ファイルを解析する場合に便利です。

XMLHttpRequest オブジェクトの responseType を「arraybuffer」に設定するだけです。

xhr.responseType = 'arraybuffer';

ネットワークからデータをダウンロードする際は、エンディアンの問題に注意する必要があります。上記のエンディアンに関するセクションをご覧ください。

ファイル API

FileReader はファイルの内容を ArrayBuffer として読み取ることができます。次に、型付き配列ビューと DataView をバッファにアタッチして、そのコンテンツを操作します。

reader.readAsArrayBuffer(file);

ここでもエンディアンに留意する必要があります。詳細については、エンディアンのセクションをご覧ください。

移行可能なオブジェクト

postMessage の転送可能なオブジェクトを使用すると、バイナリデータを他のウィンドウや Web Worker に非常に速く渡すことができます。オブジェクトを Transferable として Worker に送信すると、送信側のスレッドでオブジェクトにアクセスできなくなり、受信側の Worker がオブジェクトの所有権を取得します。これにより、送信されたデータはコピーされず、型付き配列の所有権のみが受信側に転送される、高度に最適化された実装が可能になります。

ウェブ ワーカーで Transferable オブジェクトを使用するには、ワーカーで webkitPostMessage メソッドを使用する必要があります。webkitPostMessage メソッドは postMessage と同様に動作しますが、引数を 1 つではなく 2 つ受け取ります。追加した 2 番目の引数は、ワーカーに転送するオブジェクトの配列です。

worker.webkitPostMessage(oneGBTypedArray, [oneGBTypedArray]);

オブジェクトをワーカーから取得するために、ワーカーは同じ方法でオブジェクトをメインスレッドに返します。

webkitPostMessage({results: grand, youCanHaveThisBack: oneGBTypedArray}, [oneGBTypedArray]);

コピーなし

Media Source API

最近では、メディア要素にも Media Source API の形式で型付き配列のメリットが追加されました。webkitSourceAppend を使用すると、動画データを含む型付き配列を video 要素に直接渡すことができます。これにより、動画要素によって既存の動画の後に動画データが追加されます。SourceAppend は、インタースティシャル、再生リスト、ストリーミングなど、1 つの動画要素を使って複数の動画を再生する場合に最適です。

video.webkitSourceAppend(uint8Array);

バイナリ WebSocket

また、WebSocket で型付き配列を使用して、すべてのデータ文字列を文字列化せずに済むようにすることもできます。効率的なプロトコルを作成し、ネットワーク トラフィックを最小限に抑えるのに最適です。

socket.binaryType = 'arraybuffer';

ああ!これで API レビューは終了です。型付き配列を処理するサードパーティ ライブラリを見てみましょう。

サードパーティ ライブラリ

jDataView

jDataView は、すべてのブラウザで DataView shim を実装します。DataView は、以前は WebKit 専用の機能でしたが、今では他のほとんどのブラウザでサポートされています。Mozilla のデベロッパー チームは、Firefox でも DataView を有効にするためのパッチの適用を進めています。

Chrome デベロッパー リレーションズ チームの Eric Bidelman 氏は、jDataView を使用する小さな MP3 ID3 タグリーダーの例を作成しました。このブログ投稿の使用例をご覧ください。

var dv = new jDataView(arraybuffer);

// "TAG" starts at byte -128 from EOF.
// See http://en.wikipedia.org/wiki/ID3
if (dv.getString(3, dv.byteLength - 128) == 'TAG') {
  var title = dv.getString(30, dv.tell());
  var artist = dv.getString(30, dv.tell());
  var album = dv.getString(30, dv.tell());
  var year = dv.getString(4, dv.tell());
} else {
  // no ID3v1 data found.
}

文字列エンコード

現時点では型付き配列での文字列の操作は面倒ですが、便利な stringencoding ライブラリがあります。Stringencoding は、提案された型付き配列文字列エンコード仕様を実装しているため、今後の流れを把握するのにも適しています。

次に、文字列エンコードの基本的な使用例を示します。

var uint8array = new TextEncoder(encoding).encode(string);
var string = new TextDecoder(encoding).decode(uint8array);

BitView.js

BitView.js という型付き配列用の小さなビット操作ライブラリを作成しました。その名のとおり、ビットを使用する以外は DataView とよく似ています。BitView を使用すると、ArrayBuffer の特定のビット オフセットでビットの値を取得および設定できます。BitView には、6 ビットと 12 ビットの整数を任意のビット オフセットで格納およびロードするメソッドもあります。

ディスプレイの長辺は 4, 096 ピクセル未満である傾向があるため、12 ビットの整数は画面座標の処理に適しています。32 ビット整数ではなく 12 ビット整数を使用することで、サイズを 62% 削減できます。極端な例として、座標に 64 ビット浮動小数点数を使用する Shapefile を使っていましたが、モデルは画面サイズでのみ表示されるため、精度は必要ありませんでした。前の座標からの変化をエンコードするために 6 ビットの差分を持つ 12 ビットのベース座標に切り替えた結果、ファイルサイズは 10 分の 1 に縮小されました。そのデモはこちらでご覧いただけます。

BitView.js の使用例を次に示します。

var bv = new BitView(arrayBuffer);
bv.setBit(4, 1); // Set fourth bit of arrayBuffer to 1.
bv.getBit(17); // Get 17th bit of arrayBuffer.

bv.getBit(50*8 + 3); // Get third bit of 50th byte in arrayBuffer.

bv.setInt6(3, 18); // Write 18 as a 6-bit int to bit position 3 in arrayBuffer.
bv.getInt12(9); // Read a 12-bit int from bit position 9 in arrayBuffer.

DataStream.js

型付き配列の最も注目すべき点の 1 つは、JavaScript でのバイナリ ファイルの処理が容易になる点です。文字列を 1 文字ずつ解析して手動で 2 進数などに変換する代わりに、XMLHttpRequest で ArrayBuffer を取得し、DataView を使用して直接処理できるようになりました。これにより、たとえば MP3 ファイルの読み込みや、オーディオ プレーヤーで使用するメタデータタグの読み取りが簡単に行えるようになります。または、シェープファイルを読み込んで WebGL モデルに変換します。または、JPEG から EXIF タグを読み取り、スライドショー アプリで表示します。

ArrayBuffer XHR の問題は、バッファから構造体に似たデータを読み取ることが少し面倒であることです。DataView は、複数の数値を一度にエンディアンセーフに読み取るのに適しており、型付き配列ビューは要素のサイズに揃えられたネイティブ エンディアンの配列を読み取るのに適しています。私たちが欠けていると感じるのは、データの配列と構造体を便利なエンディアンセーフ形式で読み取る方法です。DataStream.js を入力します。

DataStream.js は、配列バッファからデータのスカラー、文字列、配列、構造体をファイルのような形式で読み書きする型付き配列ライブラリです。

ArrayBuffer から浮動小数点数の配列を読み取る例:

// without DataStream.js
var dv = new DataView(buffer);
var f32 = new Float32Array(buffer.byteLength / 4);
var littleEndian = true;
for (var i = 0; i<f32.length; i++) {
  f32[i] = dv.getFloat32(i*4, littleEndian);
}

// with DataStream.js
var ds = new DataStream(buffer);
ds.endianness = DataStream.LITTLE_ENDIAN;
var f32 = ds.readFloat32Array(ds.byteLength / 4);

DataStream.js が本当に役立つのは、複雑なデータを読み取ることです。JPEG マーカーを読み取るメソッドがあるとします。

// without DataStream.js
var dv = new DataView(buffer);
var objs = [];
for (var i=0; i<buffer.byteLength;) {
  var obj = {};
  obj.tag = dv.getUint16(i);
  i += 2;
  obj.length = dv.getUint16(i);
  i += 2;
  obj.data = new Uint8Array(obj.length - 2);
  for (var j=0; j<obj.data.length; j++,i++) {
    obj.data[j] = dv.getUint8(i);
  }
  objs.push(obj);
}

// with DataStream.js
var ds = new DataStream(buffer);
ds.endianness = ds.BIG_ENDIAN;
var objs = [];
while (!ds.isEof()) {
  var obj = {};
  obj.tag = ds.readUint16();
  obj.length = ds.readUint16();
  obj.data = ds.readUint8Array(obj.length - 2);
  objs.push(obj);
}

または、DataStream.readStruct メソッドを使用して、データの構造体で読み取ります。readStruct メソッドは、構造体メンバーの型を含む構造体定義配列を受け取ります。複雑な型を処理するためのコールバック関数があり、データの配列とネストされた構造体も処理します。

// with DataStream.readStruct
ds.readStruct([
  'objs', ['[]', [ // objs: array of tag,length,data structs
    'tag', 'uint16',
    'length', 'uint16',
    'data', ['[]', 'uint8', function(s,ds){ return s.length - 2; }], // get length with a function
  '*'] // read in as many struct as there are
]);

ご覧のとおり、構造体定義は [name, type] のペアのフラットな配列です。ネストされた構造体は、型の配列を保持することで実現されます。配列は 3 要素配列を使用して定義します。2 番目の要素は配列要素の型、3 番目の要素は配列の長さです(数値、以前に読み取ったフィールドの参照、コールバック関数のいずれか)。配列定義の最初の要素は使用されていません。

このタイプに指定できる値は次のとおりです。

Number types

Unsuffixed number types use DataStream endianness.
To explicitly specify endianness, suffix the type with
'le' for little-endian or 'be' for big-endian,
e.g. 'int32be' for big-endian int32.

  'uint8' -- 8-bit unsigned int
  'uint16' -- 16-bit unsigned int
  'uint32' -- 32-bit unsigned int
  'int8' -- 8-bit int
  'int16' -- 16-bit int
  'int32' -- 32-bit int
  'float32' -- 32-bit float
  'float64' -- 64-bit float

String types

  'cstring' -- ASCII string terminated by a zero byte.
  'string:N' -- ASCII string of length N.
  'string,CHARSET:N' -- String of byteLength N encoded with given CHARSET.
  'u16string:N' -- UCS-2 string of length N in DataStream endianness.
  'u16stringle:N' -- UCS-2 string of length N in little-endian.
  'u16stringbe:N' -- UCS-2 string of length N in big-endian.

Complex types

  [name, type, name_2, type_2, ..., name_N, type_N] -- Struct

  function(dataStream, struct) {} -- Callback function to read and return data.

  {get: function(dataStream, struct) {}, set: function(dataStream, struct) {}}
  -- Getter/setter functions to reading and writing data. Handy for using the
     same struct definition for both reading and writing.

  ['', type, length] -- Array of given type and length. The length can be either
                        a number, a string that references a previously-read
                        field, or a callback function(struct, dataStream, type){}.
                        If length is set to '*', elements are read from the
                        DataStream until a read fails.

JPEG メタデータを読み取る実際の例については、こちらをご覧ください。このデモでは、JPEG ファイルのタグレベルの構造を(EXIF 解析とともに)読み取るために DataStream.js を使用し、JavaScript で JPEG 画像をデコードして表示するために jpg.js を使用します。

型付き配列の歴史

型付き配列は、WebGL の初期実装段階から始まりました。このとき、JavaScript 配列をグラフィックス ドライバに渡すことがパフォーマンスの問題を引き起こすことが判明しました。JavaScript 配列の場合、WebGL バインディングではネイティブ配列を割り当て、JavaScript 配列の上を走査してそれを埋め、配列内のすべての JavaScript オブジェクトを必要なネイティブ型にキャストする必要がありました。

データ変換のボトルネックを解消するために、Mozilla の Vladimir Vukicevic 氏は CanvasFloatArray を執筆しました。CanvasFloatArray は、JavaScript インターフェースを備えた C スタイルの浮動小数点配列です。これで、JavaScript で CanvasFloatArray を編集し、バインディングで追加の作業を行うことなく、WebGL に直接渡すことができるようになりました。その後の繰り返しで、CanvasFloatArray は WebGLFloatArray に名前変更され、さらに Float32Array に名前変更され、バッファにアクセスするための ArrayBuffer と型付き Float32Array-view に分割されました。その他の整数サイズと浮動小数点サイズ、符号付き/符号なしバリアントの型も追加されました。

設計上の考慮事項

型配列の設計は当初から、バイナリデータをネイティブ ライブラリに効率的に渡す必要性から推進されていました。このため、型付き配列ビューは、ホスト CPU のネイティブ エンディアンで整列されたデータに対して動作します。これにより、グラフィック カードへの頂点データの送信などの操作中に、JavaScript が最大限のパフォーマンスを発揮できるようになります。

DataView はファイル I/O とネットワーク I/O 用に特別に設計されており、データには常に指定されたエンディアンがあり、最大限のパフォーマンスが得られるように調整されないことがあります。

インメモリ データ アセンブリ(型付き配列ビューを使用)と I/O(DataView を使用)の分割は意識的に行われました。最新の JavaScript エンジンは、型付き配列ビューを大幅に最適化し、数値操作で高いパフォーマンスを実現します。型付き配列ビューの現在のパフォーマンス レベルは、この設計上の決定によって実現しました。

参照