Até o ES2024, um ArrayBuffer tinha um tamanho fixo desde a criação: se você precisasse de mais espaço, a única saída era alocar um buffer novo e copiar os dados antigos para dentro dele. Os resizable ArrayBuffers mudam isso, permitindo que um buffer cresça ou encolha no próprio local com resize(), além de trazer transfer() para mover a posse dos bytes entre buffers sem copiá-los.
O problema do tamanho fixo
Antes, redimensionar um buffer significava alocar um novo e copiar manualmente:
let buffer = new ArrayBuffer(16);
const view = new Uint8Array(buffer);
view.set([1, 2, 3, 4]);
// Precisa de mais espaço? Aloca outro buffer e copia tudo de novo.
const maior = new ArrayBuffer(32);
new Uint8Array(maior).set(new Uint8Array(buffer));
buffer = maior;
Isso é custoso para buffers grandes e comum em estruturas que crescem dinamicamente, como parsers de streaming, buffers de rede ou estruturas de dados binárias que não sabem o tamanho final de antemão.
Criando um buffer redimensionável
Basta passar a opção maxByteLength no construtor, definindo o limite até o qual o buffer pode crescer:
const buffer = new ArrayBuffer(16, { maxByteLength: 1024 });
console.log(buffer.byteLength); // 16 — tamanho atual
console.log(buffer.maxByteLength); // 1024 — limite máximo
console.log(buffer.resizable); // true
O maxByteLength precisa ser definido na criação e não pode ser alterado depois — é um teto reservado desde o início, de forma parecida com a capacidade de um ArrayList em outras linguagens.
resize(): crescendo e encolhendo no lugar
const buffer = new ArrayBuffer(16, { maxByteLength: 1024 });
const view = new Uint8Array(buffer);
view.set([10, 20, 30, 40]);
buffer.resize(8); // encolhe para 8 bytes
console.log(view.length); // a view já reflete o novo tamanho: 8
buffer.resize(64); // cresce de volta, até o limite de maxByteLength
console.log(buffer.byteLength); // 64
Uma TypedArray criada sobre o buffer sem um comprimento fixo (sem passar length no construtor) é chamada de length-tracking: ela acompanha automaticamente o tamanho atual do buffer a cada resize(), sem precisar recriar a view. Tentar redimensionar além de maxByteLength lança um RangeError.
transfer() e transferToFixedLength()
Esses métodos criam um novo ArrayBuffer com o mesmo conteúdo e detach (desconectam) o buffer original, que fica inutilizável — útil para transferir posse dos dados sem o custo de uma cópia defensiva:
const original = new ArrayBuffer(8, { maxByteLength: 32 });
new Uint8Array(original).set([1, 2, 3, 4, 5, 6, 7, 8]);
const novo = original.transfer(16); // novo buffer com 16 bytes, resizable
console.log(original.byteLength); // 0 — o original foi detachado
console.log(novo.byteLength); // 16
console.log(novo.resizable); // true, com o mesmo maxByteLength
const fixo = novo.transferToFixedLength(); // devolve um buffer comum, não resizable
console.log(fixo.resizable); // false
transfer() aceita um newByteLength opcional e preserva a característica resizable do buffer de origem; transferToFixedLength() sempre devolve um buffer de tamanho fixo, mesmo que o original fosse resizable.
Quando usar
- Buffers de rede ou streaming que recebem dados em pedaços e precisam crescer sem realocar e copiar a cada chunk.
- Estruturas de dados binárias (filas, buffers circulares) que mudam de tamanho com frequência em código sensível a performance.
- Passar a posse de um buffer grande para um Worker com
transfer(), evitando a cópia implícita quepostMessagefaria em outros casos. - Implementações de protocolos binários (parsers, codecs) que hoje recorrem a bibliotecas só para gerenciar realocação manual.
Cuidado com o custo de maxByteLength
Reservar um maxByteLength muito maior do que o necessário pode levar o engine a pré-alocar memória de forma menos eficiente, dependendo da implementação. Vale definir um limite realista em vez de um valor arbitrariamente alto "só para garantir".
Compatibilidade
Resizable ArrayBuffers fazem parte do ECMAScript 2024 e têm suporte amplo nos navegadores modernos (Chrome/Edge 111+, Firefox 128+, Safari 16.4+) e no Node.js recente, desde julho de 2024. Como ainda é uma adição relativamente nova, vale confirmar o suporte antes de depender dela em ambientes mais antigos.
Conclusão
Com resize() e transfer(), o ArrayBuffer deixa de ser uma estrutura rígida e ganha flexibilidade que antes só vinha de bibliotecas especializadas ou de código manual de realocação, tornando buffers binários dinâmicos uma operação nativa e eficiente.
0 Comentário
Deixe seu Comentário!
Dúvida, sugestão ou só um "valeu!" — tudo é bem-vindo por aqui.