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

Ilmari Heikkinen

はじめに

Image for: はじめに

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

型付き配列ビューは、ArrayBuffer のセグメントに対する単一型の配列のように動作します。通常の数値型にはすべて、Float32Array、Float64Array、Int32Array、Uint8Array などのわかりやすい名前のビューがあります。また、Canvas の ImageData のピクセル配列型に代わる特別なビュー(Uint8ClampedArray)もあります。

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

型付き配列の基本

Image for: 型付き配列の基本

型付き配列ビュー

型付き配列を使用するには、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 つの API の使用方法を理解すれば、他の 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);

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

たとえば、Uint8Array に保存されている画像にガンマ係数を適用する方法は次のとおりです。あまりきれいではありません。

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

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

pixels[i] *= gamma;

型付き配列ビューを作成するには、ArrayBuffer を作成してから、それを指すビューを作成することもできます。外部データを取得する API は通常 ArrayBuffer を扱うため、この方法で型付き配列ビューを取得します。

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.

型付き配列を別の型付き配列にコピーするには、型付き配列の set メソッドを使用するのが最も簡単な方法です。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

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

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 のバイトオーダーに関係なく、バイナリデータの読み取りや書き込みで一貫した正しい結果が得られます。

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

簡単な例をいくつか見てみましょう。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 サンプル プロジェクトハイダイナミック レンジ レンダリン�� デモの例をもう 1 つ示します。このデモでは、ハイダイナミック レンジ テクスチャを表す未加工のリトル エンディアン浮動小数点データをダウンロードし、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

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

ここでは、現在型付き配列を使用しているさまざまなブラウザ API について簡単に説明します。現在のクロップには、WebGL、Canvas、Web Audio API、XMLHttpRequest、WebSocket、Web Workers、Media Source API、File API が含まれます。API のリストから、型付き配列はパフォーマンスに敏感なマルチメディア処理や、データを効率的にやり取りするのに適していることがわかります。

WebGL

型付き配列は、WebGL で最初に使用されました。ここでは、バッファデータと画像データを渡すために使用されます。WebGL バッファ オブジェクトの内容を設定するには、Typed Array を使用して 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);

Canvas 2D

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

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 の transferable オブジェクトを使用すると、バイナリ データを他のウィンドウや Web Worker に渡す速度が大幅に向上します。オブジェクトを Transferable として Worker に送信すると、送信側のスレッドではオブジェクトにアクセスできなくなり、受信側の Worker がオブジェクトの所有権を取得します。これにより、送信されたデータがコピーされず、Typed Array の所有権のみがレシーバに転送される、高度に最適化された実装が可能になります。

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

worker.webkitPostMessage(oneGBTypedArray, [oneGBTypedArray]);

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

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

コピーなし、やったね!

Media Source API

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

video.webkitSourceAppend(uint8Array);

バイナリ WebSocket

WebSockets で型付き配列を使用すると、すべてのデータを文字列に変換する必要がなくなります。効率的なプロトコルを記述し、ネットワーク トラフィックを最小限に抑えるのに適しています。

socket.binaryType = 'arraybuffer';

ふう!これで API の審査は完了です。次に、型付き配列を処理するためのサードパーティ ライブラリについて説明します。

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

Image for: サードパーティ ライブラリ

jDataView

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

Chrome Developer Relations チームの 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 ライブラリが役に立ちます。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 ビットの浮動小数点数を使用するシェイプファイルを扱っていましたが、モデルは画面サイズでのみ表示される予定だったため、精度は必要ありませんでした。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 でバイナリ ファイルを簡単に処理できることです。文字列を文字ごとに解析し、文字を手動でバイナリ数に変換するのではなく、XMLHttpRequest で ArrayBuffer を取得し、DataView を使用して直接処理できるようになりました。これにより、MP3 ファイルを読み込んでメタデータ タグを読み取ったり、オーディオ プレーヤーで使用したりすることが簡単にできます。または、シェープファイルを読み込んで WebGL モデルに変換します。また、JPEG から EXIF タグを読み取って、スライドショー アプリに表示することもできます。

ArrayBuffer XHR の問題は、バッファから構造体のようなデータを読み取るのが少し面倒なことです。DataView は、エンディアン セーフな方法で一度に数値を読み取るのに適しています。型付き配列ビューは、要素サイズがアライメントされたネイティブ エンディアン数値の配列の読み取りに適しています。不足しているのは、データの配列と構造体を便利なエンディアン セーフな方法で読み取る方法です。DataStream.js を入力します。

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

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 番目の要素は配列の長さ(数値、以前に読み取ったフィールドへの参照、またはコールバック関数)です。配列定義の最初の要素は使用されていません。

type に指定できる値は次のとおりです。

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 メタデータの読み取りのライブサンプルは、こちらでご覧いただけます。このデモでは、DataStream.js を使用して JPEG ファイルのタグレベルの構造を読み取り(一部の EXIF 解析とともに)、jpg.js を使用して JPEG 画像をデコードして JavaScript で表示します。

型付き配列の歴史

Image for: 型付き配列の歴史

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

データ変換のボトルネックを解消するため、Mozilla の Vladimir Vukicevic 氏は、JavaScript インターフェースを備えた C スタイルの浮動小数点配列である CanvasFloatArray を作成しました。これで、バインディングで余分な作業を行うことなく、JavaScript で CanvasFloatArray を編集して WebGL に直接渡すことができます。その後の反復処理で、CanvasFloatArray は WebGLFloatArray に、さらに Float32Array に名前が変更され、バッファにアクセスするためのバッキング ArrayBuffer と型指定された Float32Array ビューに分割されました。また、他の整数と浮動小数点のサイズ、および符号付き/符号なしのバリエーションの型も追加されました。

設計上の考慮事項

Image for: 設計上の考慮事項

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

DataView は、ファイル I/O とネットワーク I/O 用に特別に設計されています。これらの I/O では、データには常に指定されたエンディアンが使用され、パフォーマンスを最大化するためにアライメントされない場合があります。

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

参照