Tampons de tableau en JavaScript

Dans cet article, nous examinons les tampons de tableau et comment ils sont utilisés pour gérer les données binaires brutes en JavaScript.
En JavaScript, un ArrayBuffer
est défini comme un objet qui représente un tampon de données binaires brutes générique de longueur fixe. Il vous permet de travailler directement avec des données binaires sans vous soucier du codage des caractères. Cela signifie que ArrayBuffer
gère les données binaires brutes, telles que l’utilisation de fichiers de protocole réseau.
Pour mieux le comprendre sans utiliser trop de mots inconnus, ArrayBuffer
est utilisé pour conserver et organiser les données binaires. Il gère les données binaires brutes, telles que l’utilisation de fichiers de protocole réseau et la manipulation de données brutes.
Pensez au ArrayBuffer
comme une boîte de chocolats. La taille de la boîte est fixe et ne peut contenir qu’un certain nombre de chocolats ; peu importe qu’il contienne ou non des chocolats, la taille est fixe. La boîte prend quand même de la place et a une capacité définie ; il ne peut pas être compromis, rétréci ou développé. La boîte est le ArrayBuffer
tandis que les chocolats sont les données binaires.
Utilisations de ArrayBuffer
ArrayBuffer
est utilisé pour gérer efficacement les données binaires brutes. Il est particulièrement utile lorsqu’il s’agit de protocoles réseau, d’entrées et de sorties de fichiers (E/S) et d’autres situations dans lesquelles vous devez travailler avec des données binaires.
L’objectif de l’utilisation d’ArrayBuffer est de gérer de manière transparente les données binaires brutes pendant les processus, dans des cas tels que :
- Traitement rapide des données
- Gestion des fichiers et des données réseau
- Interactions avec les API Web
- Jeux, graphiques et autres données visuelles de haute qualité
Création d’un ArrayBuffer
Pour créer un tampon de tableau, vous n’avez besoin que du ArrayBuffer
constructeur et la taille (en octets).
Voici comment cela fonctionne :
const buffer = new ArrayBuffer(8);
console.log(buffer.byteLength);
Dans l’exemple ci-dessus, nous avons créé un bloc de mémoire de taille fixe avec 8 octets. Il est actuellement vide car il ne contient aucune donnée utilisable.
Travailler avec des données binaires (tableaux typés)
Comme expliqué en introduction, ArrayBuffer
ne permet pas de manipulation directe, mais cela ne veut pas dire qu’il ne peut pas être manipulé. Pour interagir avec un ArrayBuffer
vous avez besoin de tableaux typés comme Uint8Array
, Int16Array
ou Float32Array
ou vous pouvez utiliser DataView
pour une manipulation plus flexible.
Les tableaux typés sont un type spécial de tableau qui vous permet de stocker et de manipuler des données binaires brutes dans un format spécifique comme des entiers de 8 bits, des flottants de 16 bits et plus encore. Ils n’autorisent qu’un seul type de données et ont une taille fixe.
Voici la liste des types :
- Int8Array: entiers signés 8 bits (1 octet, plage : -128 à 127)
- Uint8Array: entiers non signés de 8 bits (1 octet, plage : 0 à 255)
- Uint8ClampedArray: entiers non signés bloqués sur 8 bits (1 octet, plage : 0 à 255, mais les valeurs en dehors de cette plage sont « bloquées » à la valeur valide la plus proche)
- Int16Array: entiers signés 16 bits (2 octets, plage : -32 768 à 32 767)
- Uint16Array: entiers non signés de 16 bits (2 octets, plage : 0 à 65 535)
- Int32Array: Entiers signés 32 bits (4 octets, plage : -2 147 483 648 à 2 147 483 647)
- Tableau Uint32: entiers non signés de 32 bits (4 octets, plage : 0 à 4 294 967 295)
- Tableau Float32: nombres à virgule flottante 32 bits (4 octets, plage : environ -3,4 × 10^38 à 3,4 × 10^38)
- Tableau Float64: nombres à virgule flottante 64 bits (8 octets, plage : environ -1,8 × 10^308 à 1,8 × 10^308)
Le choix du type à utiliser dépend de ces facteurs :
- Le type de données que vous stockez: Si vous travaillez avec des nombres entiers, utilisez Int8Array, Uint8Array, Uint8ClamedArray, Int16Array, Uint16Array, Int32Array ou Uint32Array. Si vous travaillez avec des nombres décimaux, utilisez Float32Array ou Float64Array.
- Plage de valeurs: Si vous travaillez avec des valeurs négatives, utilisez un type signé comme Int8Array, Int16Array, etc. Si vous travaillez uniquement avec des valeurs positives, utilisez un type non signé comme Uint8Array, Uint16Array, etc.
- Précision et efficacité de la mémoire: Pour le bien de la mémoire de votre système, considérez toujours le type le plus petit capable de stocker votre valeur en toute sécurité. Si le type le plus petit ne fonctionne pas, vous pouvez maintenant opter pour le type suivant, plus grand. Pour les nombres compris entre 0 et 255, considérez toujours Uint8Array avant Uint32Array car il est plus efficace en termes de mémoire.
- Cas d’utilisation particuliers: Si vous travaillez avec des données de couleur telles que des pixels, telles que des images, Uint8Array ou Uint8ClampedArray est utilisé. Pour les données audio et vidéo, Float32Array est couramment utilisé.
Manipulons le tampon de tableau que nous avons créé dans l’exemple précédent (rappelez-vous qu’il est vide) en utilisant un tableau typé de Uint8Array, Int16Array et Float32Array.
const buffer = new ArrayBuffer(8);
Utilisation de Uint8Array
const uint8view = new Uint8Array(buffer);
uint8view[0] = 65;
uint8view[1] = 66;
console.log(uint8view);
Utiliser Int16Array
const int16View = new Int16Array(buffer);
int16View[0] = 300;
int16View[1] = -500;
console.log(int16View);
Utilisation de Float32Array
const float32View = new Float32Array(buffer);
float32View[0] = 3.14;
console.log(float32View);
Lecture et écriture faciles (DataView)
Contrairement aux tableaux typés, qui n’autorisent qu’un seul type de données et une taille fixe, DataView
vous permet de lire et d’écrire différents types de tailles de données, ce qui facilite grandement le travail avec ArrayBuffer
.
Voici une liste de types dans DataView :
- setInt8(offset, value) : entiers signés 8 bits
- setUint8(offset, value) : entiers non signés de 8 bits
- setInt16(offset, value) : entiers signés 16 bits
- setUint16(offset, value) : entiers non signés de 16 bits
- setInt32(offset, value) : entiers signés 32 bits
- setUint32(offset, value) : entiers non signés de 32 bits
- setFloat32(offset, valeur) : virgule flottante 32 bits
- setFloat64(offset, valeur) : virgule flottante 64 bits
Le offset
est l’index ou la position d’un octet dans le tampon du tableau. Considérez-le comme un emplacement pour stocker de manière unique un octet dans un tampon pendant que value
est l’octet à stocker.
Voyons comment utiliser DataView.
Création d’un ArrayBuffer et d’un DataView
const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
Dans le code ci-dessus, un nouveau ArrayBuffer
avec 8 octets de mémoire est créé. Il est initialement vide et est stocké dans un nom de variable buffer
. Nous avons ensuite utilisé DataView
lire et écrire différents types de données pour le ArrayBuffer
.
Écrire des données dans le tampon
view.setInt8(0, 100);
view.setUint16(1, 500);
view.setFloat32(3, 3.14);
console.log(view);
Dans le code ci-dessus, nous stockons trois types de données différents dans le tampon : setInt8, setUint16 et setFloat32 à l’aide de DataView.
setInt8(0, 100)
a un décalage de 0 et une valeur de 100 ; il stocke 100 à la position d’octet 0. setInt8
peut être positif ou négatif, mais 100 est positif.
setUint16(1, 500)
a un décalage de 1 et une valeur de 500. Il stocke 500 dans les positions d’octet 1 et 2 (2 octets). En effet, en binaire, 500 correspond à 00000001 11110100. Le premier octet prend la position 1, tandis que le deuxième octet prend la position 2.
setFloat32(3, 3.14)
a un décalage de 3 et une valeur de 3,14 ; il stocke 3.14 en position d’octet 3 à 6 (4 octets). Cela est dû à la façon dont les nombres à virgule flottante sont représentés dans l’ordinateur. Float32 utilise la norme IEEE 754 et prend 4 octets selon l’ordinateur. En binaire, 3.14 vaut 01000000 01001100 11110011 11010101. Le premier octet prend la position 1, le deuxième octet prend la position 2, le troisième octet prend la position 3 et le quatrième octet prend la position 4.
Ce sont tous des types de données différents stockés dans un tampon, qui ne peuvent être obtenus qu’en utilisant DataView
.
Lecture des données du tampon
console.log(view.getInt8(0));
console.log(view.getUint16(1));
console.log(view.getFloat32(3));
Dans le code ci-dessus, nous lisons le code des différents types de données stockés dans le tampon et les obtenons en fonction de leur décalage.
Conversion de chaînes vers et depuis ArrayBuffer
JavaScript fournit plusieurs méthodes pour convertir entre les chaînes et ArrayBuffers
ce qui est essentiel pour des tâches telles que l’encodage, le décodage et la gestion des flux de données. On ne peut pas parler de conversion entre chaînes et ArrayBuffer
sans en parler TextEncoder
et TextDecoder
.
Convertir une chaîne en ArrayBuffer
Pour convertir une chaîne en ArrayBuffer, vous devez généralement coder la chaîne au format binaire. Le codage le plus courant est UTF-8.
Voici comment y parvenir :
function stringToArrayBuffer(str) {
let encoder = new TextEncoder();
return encoder.encode(str).buffer;
}
let myString = "Hello, World";
let buffer = stringToArrayBuffer(myString);
console.log(buffer);
Le code ci-dessus est une fonction permettant de convertir une chaîne en tampon de tableau à l’aide de TextEncoder.
Convertir un ArrayBuffer en chaîne
Pour convertir un ArrayBuffer en chaîne, vous devez décoder les données binaires. L’objet TextDecoder est utilisé pour décoder un ArrayBuffer en chaîne.
function arrayBufferToString(buffer) {
let decoder = new TextDecoder();
return decoder.decode(new Uint8Array(buffer));
}
let decodedString = arrayBufferToString(buffer);
console.log(decodedString);
Dans le code ci-dessus, nous avons utilisé la fonction pour convertir le arrayBuffer en chaîne en utilisant TextDecoder
.
Gestion de différents encodages
Bien que UTF-8 soit le codage le plus courant, vous devrez parfois gérer d’autres codages. Le TextEncoder
et TextDecoder
peut être utilisé avec différents encodages en spécifiant simplement le type d’encodage comme indiqué ci-dessous :
let encoder = new TextEncoder("utf-16");
let buffer = encoder.encode("Hello, World!");
let string = decoder.decode(buffer);
console.log(string);
Récupération de données binaires à l’aide d’ArrayBuffer
Les API Web nécessitent souvent que les données soient au format binaire. Par exemple, lorsque vous utilisez le Fetch
API pour télécharger des fichiers binaires, la réponse est un ArrayBuffer. La conversion de ces données binaires en chaîne peut être nécessaire pour un traitement ou un affichage ultérieur.
fetch("example.com/data")
.then((response) => response.arrayBuffer())
.then((buffer) => {
let text = arrayBufferToString(buffer);
console.log(text);
});
Application de ArrayBuffer
ArrayBuffer est important lorsqu’il s’agit de tâches gourmandes en performances, en particulier lorsqu’elles impliquent des données binaires.
Voici quelques-unes de ses applications dans les logiciels modernes :
- Applications de partage de fichiers ou de gestion de fichiers (images, vidéos, audio, PDF, etc.) : les applications Web traitent souvent des fichiers volumineux, ce qui peut parfois ralentir l’ordinateur ou provoquer des ralentissements du système. Avec l’aide d’ArrayBuffer, ce processus est géré efficacement sans ralentissement.
let fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener("change", function (event) {
let file = event.target.files[0];
let reader = new FileReader();
reader.onload = function () {
let arrayBuffer = reader.result;
let text = arrayBufferToString(arrayBuffer);
console.log(text);
};
reader.readAsArrayBuffer(file);
});
Dans le code ci-dessus, input[type="file"]
est une balise HTML permettant de télécharger un fichier. Le fichier est lu comme un tampon de tableau puis converti en chaîne à afficher dans la console.
- Applications de streaming comme Netflix ou YouTube qui traitent des données volumineuses : la meilleure façon de procéder est de les traiter en morceaux au lieu de les charger en une seule fois. ArrayBuffer aide à gérer et gérer cela.
- Dans les interactions des API Web : Fetch API, WebSocket, Socket.IO et plus de travail avec des données binaires brutes. ArrayBuffer contribue également à assurer un envoi et une réception fluides de ces données.
- Jeux en ligne : les plateformes de jeux sont des applications axées sur les performances. Ils utilisent des bibliothèques telles que des moteurs de jeu et le rendu 3D, et ces bibliothèques utilisent ArrayBuffer pour gérer efficacement les textures, les modèles et les animations.
- Authentification biométrique : les tampons de tableau sont largement utilisés pour représenter les clés d’accès, ce qui permet aux utilisateurs de s’authentifier sur les applications en utilisant leurs données biométriques plutôt que des mots de passe classiques. La structure de la charge utile reçue lorsque les clés d’accès sont créées ou utilisées pour l’authentification se présente sous la forme de tampons de tableau.
Meilleures pratiques et considérations en matière de performances
Il est clair qu’ArrayBuffer est important pour gérer des applications hautes performances. Cependant, ces bonnes pratiques doivent être prises en compte pour une utilisation optimale :
- N’abusez pas de DataView : lorsque vous travaillez avec un seul type de données, utilisez TypedArray, qui est plus rapide que DataView. Évitez DataView sauf si vous devez travailler avec des types de données mixtes.
- Évitez la duplication inutile d’ArrayBuffer : ArrayBuffer est stocké en mémoire et, lorsqu’il est créé plusieurs fois, peut gaspiller de la mémoire. Essayez d’éviter autant que possible les copies de tampon de tableau. Lorsque vous travaillez avec des parties d’un tampon, utilisez
subarray()
au lieu deslice()
quand cela est possible. - Effacez toujours la mémoire lorsque l’ArrayBuffer n’est plus nécessaire. ArrayBuffer ne peut pas être suivi directement en mémoire, surtout s’il est volumineux ; vous pouvez effacer ou annuler manuellement ses références pour libérer de la mémoire.
Voici comment procéder :
let buffer = new ArrayBuffer(8);
buffer = null;
- Utilisez des flux pour récupérer des fichiers binaires volumineux : le chargement simultané d’un grand nombre de données binaires consomme de la mémoire et peut provoquer le blocage du thread principal. Utilisez des flux pour traiter les données par morceaux. Un exemple de ce flux est
response.body.getReader()
.
Voici le code expliquant cela :
async function fetchLargeFile(url) {
const response = await fetch(url);
const reader = response.body.getReader();
const chunks = [];
let receivedLength = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
receivedLength += value.length;
console.log(`Received ${receivedLength} bytes so far...`);
}
const fullData = new Uint8Array(receivedLength);
let position = 0;
for (const chunk of chunks) {
fullData.set(chunk, position);
position += chunk.length;
}
console.log("Download complete!");
return fullData;
}
fetchLargeFile("https://example.com/large-file.bin").then((data) => {
console.log("Final file size:", data.length);
});
Nous avons créé une fonction asynchrone appelée fetchLargeFile
qui accepte une URL comme argument. Nous utilisons getReader
pour lire les fichiers en petits morceaux au lieu de les télécharger en une seule fois. Nous créons un tableau appelé chunks
pour collecter et rassembler tous les petits morceaux. Nous utilisons une boucle while pour lire le fichier par petites parties et suivre le processus. Nous stockons ensuite chaque morceau dans le chunk
tableau et mettre à jour la progression. Nous combinons tous les morceaux en un seul fichier final et enregistrons Download complete!
lorsque le processus est terminé.
- Pour le multithread, utilisez
SharedArrayBuffer
. Certaines applications (par exemple, Web Workers) nécessitent un multitâche au lieu d’un seul mode de traitement ; il est recommandé d’utiliserSharedArrayBuffer
pour partager des données entre les threads sans copier. Ceci est le plus souvent utilisé pour des tâches hautes performances telles que le traitement vidéo ou la communication en temps réel.
Voici comment utiliser SharedArrayBuffer
:
const buffer = new SharedArrayBuffer(1024);
const uint8Array = new Uint8Array(buffer);
Conclusion
ArrayBuffer en JavaScript permet de gérer efficacement les données binaires. Bien que cela puisse paraître complexe à comprendre, il peut aider à développer des applications logicielles performantes lorsqu’il est correctement mis en œuvre. En fait, c’est la technologie qui se cache derrière de nombreuses plateformes de streaming à succès et d’autres applications en temps réel.
Source link