Работа с типизированными массивами и буферами в JavaScript

Работа с типизированными массивами и буферами в JavaScript


Теория

Что такое буфер? Буфер это массив для хранения сырых данных в с определённой длиной в n байтов. Буфер невозможно изменять, для это нужен другой объект, представляющий эти данные. Этот объект нужен для записи и изменения данных буфера, не трогая сам буфер.

Для создания буферов есть ArrayBuffer, а для отображения данных используются либо типовые массивы, либо DataView. И у обоих можно устанавливать ячейки.

buf = new ArrayBuffer(16) // byteLength: 16
view = new DataView(buf) // buffer: ArrayBuffer
view.setFloat64(0, 20.4)
view.getFloat64(0)  // 20.4
view.setInt16(0, 500)
view.getInt16(0) // 500
view.getFloat64(0) // 3.046172450794506e-299

Можно заметить одну странность, мы просматриваем ячейку в формате Int16 как Float64. В DataView можно ставить один тип данных ячейку, а просматривать как другой.

Таблица типовых массивов

Ранее я упомянул типовые массивы. В отличие от DataView здесь нельзя менять тип данных. И он выглядит как обычный массив. Причём каждый тип данных по-своему распределяет буффер.

b = new ArrayBuffer(64);
new Uint16Array(b)  
// Uint16Array(32) [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, … ]
new Uint32Array(b) 
// Uint32Array(16) [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, … ]
new Uint8Array(b)  
// Uint8Array(64) [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, … ]

У типовых массивов работают те же методы, что и у обычных, за исключением того что нельзя добавлять новые ячейки, потому что буффер неизменяем.

b = new ArrayBuffer(64)
u = new Uint16Array(b)
u.fill(2) // Uint16Array(32) [ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, … ]
u.slice(0,20) // Uint16Array(20) [ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, … ]

Также у типовых массивов и DataView есть свойство byteOffset, с помощью которого можно его расширить:

b = new ArrayBuffer(64);
u = new Uint16Array(b, 16) // смещение на 16 байтов
console.log(u.length) // 24

Практика

Буфера используются в веб API, вот несколько из них:

XMLHttpRequest

const xhr = new XMLHttpRequest();
xhr.open('GET', someUrl);
xhr.responseType = 'arraybuffer';

xhr.onload = function () {
    const arrayBuffer = xhr.response;
    ···
};

xhr.send();

Fetch API

fetch(url)
.then(request => request.arrayBuffer())
.then(arrayBuffer => ···);

Report Page