Array yang memiliki jenis - Data biner di browser

Ilmari Heikkinen

Pengantar

Array Berjenis adalah tambahan yang relatif baru pada browser, yang lahir dari kebutuhan untuk memiliki cara yang efisien untuk menangani data biner di WebGL. {i>Typed Array<i} adalah slab memori dengan tampilan berjenis di dalamnya, seperti cara kerja {i>array<i} di C. Karena Array Berjenis didukung oleh memori mentah, mesin JavaScript bisa meneruskan memori langsung ke library native tanpa harus dengan susah payah mengonversi data ke representasi native. Hasilnya, array yang diketik berperforma jauh lebih baik daripada array JavaScript untuk meneruskan data ke WebGL dan API lain yang menangani data biner.

Tampilan array berjenis berfungsi seperti array berjenis tunggal pada segmen ArrayBuffer. Ada tampilan untuk semua jenis numerik biasa, dengan nama deskriptif mandiri seperti Float32Array, Float64Array, Int32Array, dan Uint8Array. Ada juga tampilan khusus yang telah menggantikan jenis array piksel di ImageData Canvas: Uint8ClampedArray.

DataView adalah jenis tampilan kedua dan dimaksudkan untuk menangani data yang heterogen. Daripada memiliki API mirip array, objek DataView menyediakan API get/set untuk membaca dan menulis jenis data arbitrer pada offset byte arbitrer. DataView berfungsi sangat baik untuk membaca dan menulis header file dan data lainnya yang mirip struct.

Dasar-dasar penggunaan Array yang Berjenis

Tampilan array yang memiliki jenis

Untuk menggunakan Array Berjenis, Anda perlu membuat ArrayBuffer dan tampilannya. Cara termudah adalah dengan membuat tampilan array yang memiliki jenis dengan ukuran dan jenis yang diinginkan.

// 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];

Ada beberapa jenis tampilan array yang memiliki jenis ini. Mereka semua memiliki API yang sama, jadi setelah mengetahui cara menggunakannya, Anda akan tahu cara menggunakan semuanya. Saya akan membuat salah satu dari setiap tampilan array berjenis yang saat ini ada pada contoh berikutnya.

// 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);

Yang terakhir sedikit istimewa, ia menjepit nilai input antara 0 dan 255. Hal ini sangat berguna untuk algoritma pemrosesan gambar Canvas, karena kini Anda tidak perlu membatasi perhitungan pemrosesan gambar secara manual untuk menghindari melebihi rentang 8 bit.

Misalnya, berikut ini cara menerapkan faktor gamma pada gambar yang disimpan dalam Uint8Array. Tidak terlalu bagus:

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

Dengan Uint8ClampedArray Anda dapat melewati penjepit manual:

pixels[i] *= gamma;

Cara lain untuk membuat tampilan array yang diketik adalah dengan membuat ArrayBuffer terlebih dahulu, kemudian membuat tampilan yang mengarah kenya. API yang memberi Anda data eksternal biasanya menangani ArrayBuffers, jadi ini adalah cara Anda mendapatkan tampilan array yang memiliki jenis.

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);

Anda juga dapat memiliki beberapa tampilan pada ArrayBuffer yang sama.

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

Untuk menyalin array yang memiliki jenis ke array lain yang memiliki jenis ini, cara tercepat adalah menggunakan metode set array yang memiliki jenis ini. Untuk penggunaan seperti memcpy, buat Uint8Array ke buffer tampilan dan gunakan set untuk menyalin data.

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

Untuk menggunakan ArrayBuffer yang berisi data dengan jenis heterogen, cara termudah adalah menggunakan DataView ke buffer. Misalkan kita memiliki format file yang memiliki header dengan int 8-bit tanpa label diikuti oleh dua int 16-bit, diikuti oleh array payload float 32-bit. Membaca artikel ini kembali dengan tampilan array yang diketik bisa dilakukan, tetapi sedikit merepotkan. Dengan DataView, kita dapat membaca header dan menggunakan tampilan array yang memiliki jenis untuk array 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);
}

Pada contoh di atas, semua nilai yang saya baca adalah big-endian. Jika nilai dalam buffer adalah little-endian, Anda dapat meneruskan parameter littleEndian opsional ke pengambil:

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

Perhatikan, tampilan array yang diketik selalu dalam urutan byte native. Hal ini untuk mempercepat prosesnya. Anda harus menggunakan DataView untuk membaca dan menulis data di mana endianness akan menjadi masalah.

DataView juga memiliki metode untuk menulis nilai ke buffer. Penyetel ini diberi nama dengan cara yang sama seperti pengambil, yaitu "set" diikuti dengan jenis data.

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

Diskusi {i>endianness<i}

Endianness, atau urutan byte, adalah urutan penyimpanan angka multi-byte di dalam memori komputer. Istilah big-endian menggambarkan arsitektur CPU yang menyimpan byte yang paling signifikan terlebih dahulu; little-endian, byte paling tidak signifikan terlebih dahulu. Endianness mana yang digunakan dalam arsitektur CPU tertentu sepenuhnya bersifat tidak tentu; ada alasan yang baik untuk memilih salah satunya. Bahkan, sebagian CPU dapat dikonfigurasi untuk mendukung data {i>big-endian<i} dan {i>small-endian<i}.

Mengapa Anda perlu mengkhawatirkan endianness? Alasannya sederhana. Saat membaca atau menulis data dari disk atau jaringan, endianness data harus ditentukan. Hal ini memastikan bahwa data ditafsirkan dengan benar, terlepas dari endian CPU yang bekerja dengannya. Di dunia jaringan kita yang semakin berkembang, kita perlu mendukung dengan benar semua jenis perangkat, big-endian atau big-endian, yang mungkin perlu bekerja dengan data biner yang berasal dari server atau rekan lain di jaringan.

Antarmuka DataView dirancang khusus untuk membaca dan menulis data ke dan dari file serta jaringan. DataView beroperasi berdasarkan data dengan endianness yang ditentukan. Endianness, besar atau kecil, harus ditentukan dengan setiap akses dari setiap nilai, memastikan bahwa Anda mendapatkan hasil yang konsisten dan benar saat membaca atau menulis data biner, tidak peduli tingkat endian CPU yang dijalankan oleh browser.

Biasanya, bila aplikasi Anda membaca data biner dari server, Anda harus memindainya sekali untuk mengubahnya menjadi struktur data yang digunakan aplikasi Anda secara internal. DataView harus digunakan selama fase ini. Sebaiknya gunakan tampilan array berjenis multi-byte (Int16Array, Uint16Array, dll.) secara langsung dengan data yang diambil melalui XMLHttpRequest, FileReader, atau API input/output lainnya, karena tampilan array yang diketik menggunakan endianness asli CPU. Selengkapnya akan dibahas nanti.

Mari kita lihat beberapa contoh sederhana. Format file Windows BMP sebelumnya merupakan format standar untuk menyimpan gambar di versi awal Windows. Dokumentasi yang ditautkan di atas dengan jelas menunjukkan bahwa semua nilai integer dalam file disimpan dalam format little-endian. Berikut adalah cuplikan kode yang menguraikan awal header BMP menggunakan library DataStream.js yang menyertai artikel ini:

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();
  // ...
}

Berikut contoh lain, contoh ini dari demo rendering High Dynamic Range dalam project contoh WebGL. Demo ini mendownload data floating point mentah yang mewakili tekstur rentang dinamis tinggi, dan perlu menguploadnya ke WebGL. Berikut ini adalah cuplikan kode yang menafsirkan nilai floating point dengan benar pada semua arsitektur CPU. Asumsikan variabel “arrayBuffer” adalah ArrayBuffer yang baru saja didownload dari server melalui XMLHttpRequest:

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);

Aturan praktisnya adalah: setelah menerima data biner dari server web, buat satu penerusan data dengan DataView. Baca masing-masing nilai numerik dan simpan dalam beberapa struktur data lain, baik objek JavaScript (untuk data terstruktur dalam jumlah kecil) maupun tampilan array yang diketik (untuk blok data yang besar). Ini akan memastikan bahwa kode Anda berfungsi dengan benar pada semua jenis CPU. Gunakan juga DataView untuk menulis data ke file atau jaringan, dan pastikan untuk menentukan argumen littleEndian dengan tepat ke berbagai metode set untuk menghasilkan format file yang sedang Anda buat atau gunakan.

Ingat, semua data yang berjalan melalui jaringan secara implisit memiliki format dan endianness (setidaknya, untuk nilai multi-byte). Pastikan untuk mendefinisikan dan mendokumentasikan format semua data yang dikirimkan aplikasi Anda melalui jaringan dengan jelas.

API Browser yang menggunakan Array Berjenis

Saya akan memberikan ringkasan singkat mengenai berbagai API browser yang saat ini menggunakan Array Berjenis. Pemangkasan saat ini mencakup WebGL, Canvas, Web Audio API, XMLHttpRequests, WebSockets, Web Workers, Media Source API, dan File API. Dari daftar API, Anda dapat melihat bahwa Typed Array sangat cocok untuk pekerjaan multimedia yang sensitif terhadap performa serta meneruskan data secara efisien.

WebGL

Penggunaan pertama Array Berjenis adalah di WebGL, yang digunakan untuk meneruskan data buffer dan data gambar. Untuk menyetel konten objek buffer WebGL, gunakan panggilan gl.bufferData() dengan Array Berjenis.

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

{i>Typed Array<i} juga digunakan untuk meneruskan data tekstur. Berikut ini contoh dasar penerusan konten tekstur menggunakan Array Berjenis.

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
);

Anda juga memerlukan Array yang Diketik untuk membaca piksel dari konteks WebGL.

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

Kanvas 2D

Baru-baru ini, objek ImageData Canvas dibuat untuk berfungsi dengan spesifikasi Array yang Dijeniskan. Sekarang Anda bisa mendapatkan representasi Array Berjenis dari piksel pada elemen kanvas. Hal ini sangat membantu karena kini Anda juga bisa membuat dan mengedit array piksel kanvas tanpa harus mengutak-atik elemen kanvas.

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

XMLHttpRequest2

XMLHttpRequest mendapatkan peningkatan Array Berjenis dan sekarang Anda dapat menerima respons Array Berjenis, tanpa harus mengurai string JavaScript ke dalam Array Berjenis. Cara ini sangat praktis untuk meneruskan data yang diambil langsung ke API multimedia dan untuk mengurai file biner yang diambil dari jaringan.

Yang harus Anda lakukan adalah menetapkan responseType objek XMLHttpRequest ke 'arraybuffer'.

xhr.responseType = 'arraybuffer';

Ingatlah bahwa Anda harus mengetahui masalah endian saat mendownload data dari jaringan. Lihat bagian tentang endianness di atas.

File API

FileReader dapat membaca konten file sebagai ArrayBuffer. Anda kemudian dapat melampirkan tampilan array yang diketik dan DataViews ke buffer untuk memanipulasi kontennya.

reader.readAsArrayBuffer(file);

Anda juga harus mengingat endianness di sini. Lihat bagian endianness untuk detailnya.

Objek yang dapat ditransfer

Objek yang dapat ditransfer di postMessage membuat penerusan data biner ke jendela dan Pekerja Web lain jauh lebih cepat. Saat Anda mengirim objek ke Pekerja sebagai Dapat Ditransfer, objek menjadi tidak dapat diakses dalam thread pengirim dan Pekerja penerima mendapatkan kepemilikan objek. Hal ini memungkinkan implementasi yang sangat optimal di mana data yang dikirim tidak disalin, hanya kepemilikan Array Berjenis yang ditransfer ke penerima.

Untuk menggunakan objek yang Dapat Ditransfer dengan Web Worker, Anda perlu menggunakan metode webkitPostMessage pada pekerja. Metode webkitPostMessage berfungsi seperti postMessage, tetapi memerlukan dua argumen, bukan hanya satu. Argumen kedua yang ditambahkan adalah array objek yang ingin Anda transfer ke pekerja.

worker.webkitPostMessage(oneGBTypedArray, [oneGBTypedArray]);

Untuk mendapatkan objek kembali dari pekerja, worker dapat meneruskannya kembali ke thread utama dengan cara yang sama.

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

Tidak ada salinan, wow!

API Sumber Media

Baru-baru ini, elemen media juga mendapatkan beberapa manfaat Array Berjenis dalam bentuk Media Source API. Anda dapat langsung meneruskan Array Berjenis yang berisi data video ke elemen video menggunakan webkitSourceAppend. Hal ini membuat elemen video menambahkan data video setelah video yang ada. SourceAppend sangat bagus untuk melakukan interstisial, daftar putar, streaming, dan penggunaan lainnya di mana Anda mungkin ingin memutar beberapa video menggunakan elemen video tunggal.

video.webkitSourceAppend(uint8Array);

WebSocket Biner

Anda juga dapat menggunakan Array Berjenis dengan WebSockets agar tidak perlu merangkai semua data Anda. Bagus untuk menulis protokol yang efisien dan meminimalkan lalu lintas jaringan.

socket.binaryType = 'arraybuffer';

Baguslah! Kita telah sampai di akhir peninjauan API. Mari kita beralih ke library pihak ketiga untuk menangani Array Berjenis.

Library pihak ketiga

jDataView

jDataView menerapkan shim DataView untuk semua browser. DataView sebelumnya hanya merupakan fitur WebKit, tetapi sekarang didukung oleh sebagian besar browser lain. Tim developer Mozilla sedang dalam proses mendapatkan patch untuk mengaktifkan DataView di Firefox.

Eric Bidelman dari tim Developer Relations Chrome menulis contoh kecil pembaca tag ID3 MP3 yang menggunakan jDataView. Berikut adalah contoh penggunaan dari postingan blog tersebut:

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.
}

encoding string

Menggunakan string dalam Typed Array agak merepotkan saat ini, tetapi ada library stringencoding yang dapat membantu hal tersebut. Stringencoding menerapkan spesifikasi encoding string Array Jenis yang diusulkan, jadi ini juga merupakan cara yang baik untuk mengetahui apa yang akan datang.

Berikut ini contoh penggunaan dasar encoding string:

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

BitView.js

Saya telah menulis sedikit library manipulasi untuk Typed Array yang disebut BitView.js. Seperti namanya, fungsi ini mirip dengan DataView, tetapi berfungsi dengan bit. Dengan BitView, Anda bisa mendapatkan dan menetapkan nilai bit pada offset bit tertentu dalam ArrayBuffer. BitView juga memiliki metode untuk menyimpan dan memuat int 6-bit dan 12-bit pada offset bit arbitrer.

Int 12-bit bagus untuk bekerja dengan koordinat layar, karena tampilan cenderung memiliki kurang dari 4096 piksel di sepanjang dimensi yang lebih panjang. Dengan menggunakan int 12-bit alih-alih int 32-bit, Anda mendapatkan pengurangan ukuran 62%. Untuk contoh yang lebih ekstrem, saya bekerja dengan Shapefile yang menggunakan float 64-bit untuk koordinat, tetapi saya tidak memerlukan presisi karena model hanya akan ditampilkan pada ukuran layar. Beralih ke koordinat dasar 12-bit dengan delta 6-bit untuk mengenkode perubahan dari koordinat sebelumnya membuat ukuran file turun ke sepersepuluh. Anda dapat melihat demonya di sini.

Berikut adalah contoh penggunaan 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

Salah satu hal paling menarik tentang jenis array adalah bagaimana mereka menangani file biner dalam JavaScript dengan lebih mudah. Daripada mengurai karakter string demi karakter dan mengonversi karakter secara manual menjadi bilangan biner dan semacamnya, Anda kini bisa mendapatkan ArrayBuffer dengan XMLHttpRequest dan langsung memprosesnya menggunakan DataView. Hal ini memudahkan, misalnya, memuat file MP3 dan membaca tag metadata untuk digunakan di pemutar audio Anda. Atau muat shapefile dan ubah menjadi model WebGL. Atau baca tag EXIF pada JPEG dan tampilkan di aplikasi slideshow Anda.

Masalah dengan ArrayBuffer XHR adalah pembacaan data seperti struct dari buffer agak merepotkan. DataView baik untuk membaca beberapa angka sekaligus dengan cara yang aman secara endian, tampilan array yang diketik cocok untuk membaca array bilangan endian native yang diselaraskan dengan ukuran elemen. Apa yang kami rasa hilang adalah cara untuk membaca dalam array dan struktur data dengan cara yang aman secara endian. Masukkan DataStream.js.

DataStream.js adalah library Array Berjenis yang membaca dan menulis skalar, string, array, dan struct data dari ArrayBuffer dengan cara yang mirip dengan file.

Contoh pembacaan dalam array float dari 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);

Tempat DataStream.js sangat berguna adalah dalam membaca data yang lebih kompleks. Misalkan Anda memiliki metode yang membaca penanda 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);
}

Atau gunakan metode DataStream.readStruct untuk membaca struktur data. Metode readStruct menggunakan array definisi struct yang berisi jenis anggota struct. SDK ini memiliki fungsi callback untuk menangani jenis kompleks dan juga menangani array data serta struct bertingkat:

// 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
]);

Seperti yang dapat Anda lihat, definisi struct adalah array datar dari pasangan [name, type]. Struct bertingkat dilakukan dengan memiliki array untuk jenisnya. Array didefinisikan dengan menggunakan array tiga elemen dengan elemen kedua adalah jenis elemen array dan elemen ketiga adalah panjang array (baik sebagai angka, sebagai referensi ke kolom yang dibaca sebelumnya atau sebagai fungsi callback). Elemen pertama dari definisi array tidak digunakan.

Nilai yang memungkinkan untuk jenis ini adalah sebagai berikut:

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.

Anda dapat melihat contoh langsung pembacaan dalam metadata JPEG di sini. Demo menggunakan DataStream.js untuk membaca struktur tingkat tag file JPEG (bersama dengan beberapa penguraian EXIF), dan jpg.js untuk mendekode dan menampilkan gambar JPEG di JavaScript.

Histori Array yang Berjenis

Array yang Diketik memulai awalnya pada tahap implementasi awal WebGL, saat kami menemukan bahwa meneruskan array JavaScript ke driver grafis menyebabkan masalah performa. Dengan array JavaScript, binding WebGL harus mengalokasikan array native dan mengisinya dengan berjalan di atas array JavaScript dan mentransmisikan setiap objek JavaScript dalam array ke jenis native yang diperlukan.

Untuk memperbaiki bottleneck konversi data, Vladimir Vukicevic dari Mozilla menulis CanvasFloatArray: sebuah array mengambang bergaya C dengan antarmuka JavaScript. Sekarang Anda dapat mengedit CanvasFloatArray di JavaScript dan meneruskannya langsung ke WebGL tanpa harus melakukan pekerjaan tambahan di binding. Dalam iterasi lebih lanjut, CanvasFloatArray diganti namanya menjadi WebGLFloatArray, yang selanjutnya diganti namanya menjadi Float32Array dan dibagi menjadi ArrayBuffer pendukung dan Float32Array-view yang diketik untuk mengakses buffer. Jenis juga ditambahkan untuk ukuran bilangan bulat dan floating point lainnya serta varian bertanda tangan/tidak bertanda tangan.

Pertimbangan desain

Sejak awal, desain Typed Array didorong oleh kebutuhan untuk meneruskan data biner ke library native secara efisien. Karena alasan ini, tampilan array yang diketik beroperasi pada data yang diselaraskan dalam endianness native CPU host. Keputusan ini memungkinkan JavaScript mencapai performa maksimum selama operasi, seperti mengirimkan data verteks ke kartu grafis.

DataView secara khusus dirancang untuk I/O file dan jaringan, dengan data yang selalu memiliki endianness yang ditentukan, dan mungkin tidak diselaraskan untuk performa maksimum.

Perpecahan desain antara assembly data dalam memori (menggunakan tampilan array yang diketik) dan I/O (menggunakan DataView) adalah hal yang sadar. Mesin JavaScript modern sangat mengoptimalkan tampilan array yang diketik, dan mencapai performa tinggi pada operasi numerik dengannya. Tingkat kinerja tampilan array yang diketik saat ini dimungkinkan oleh keputusan desain ini.

Referensi