TypedArray dans TypeScript
Cet article explique TypedArray dans TypeScript.
Nous allons expliquer les TypedArray en TypeScript, y compris avec des exemples pratiques.
YouTube Video
TypedArray dans TypeScript
TypedArray est un mécanisme pour gérer efficacement les données binaires. C'est particulièrement utile pour les opérations binaires de bas niveau comme les grandes images, les flux d’octets réseau et les tableaux numériques pour WebGL.
Comment créer un ArrayBuffer
ArrayBuffer représente une zone de mémoire de longueur fixe en octets. Commencez par créer un buffer et vérifier sa taille et sa longueur en octets.
1// Create an ArrayBuffer of 16 bytes
2const buffer: ArrayBuffer = new ArrayBuffer(16);
3console.log("buffer.byteLength:", buffer.byteLength); // 16
- Ce code crée une zone vide de 16 octets.
ArrayBuffern'a pas de fonctions de lecture/écriture directement, il faut donc y accéder via unTypedArrayou unDataView.
Types de TypedArray
Il existe de nombreux types de TypedArray, comme les suivants. Ils varient en fonction du type de données et de leur taille que chaque type gère.
| TypedArray | Type de données | Taille en bits |
|---|---|---|
Int8Array |
Entier 8 bits | 8 bits |
Uint8Array |
Entier non signé 8 bits | 8 bits |
Uint8ClampedArray |
Entier non signé 8 bits limité | 8 bits |
Int16Array |
Entier 16 bits | 16 bits |
Uint16Array |
Entier non signé 16 bits | 16 bits |
Int32Array |
Entier 32 bits | 32 bits |
Uint32Array |
Entier non signé 32 bits | 32 bits |
Float32Array |
Nombre à virgule flottante 32 bits | 32 bits |
Float64Array |
Nombre à virgule flottante 64 bits | 64 bits |
TypedArray de base (Uint8Array, Int16Array, Float32Array, etc.)
TypedArray crée une « vue typée » au-dessus d’un ArrayBuffer. Voici des exemples de création et d’utilisation de quelques TypedArray typiques.
1// Create a buffer and different typed views over it
2const buf = new ArrayBuffer(8); // 8 bytes
3
4// Create views
5const u8 = new Uint8Array(buf); // 8 x uint8
6const i16 = new Int16Array(buf); // 4 x int16 (since each int16 is 2 bytes)
7const f32 = new Float32Array(buf); // 2 x float32 (4 bytes each)
8
9console.log("Uint8 length:", u8.length);
10console.log("Int16 length:", i16.length);
11console.log("Float32 length:", f32.length);- En créant plusieurs vues sur le même
ArrayBuffer, vous pouvez lire et écrire dans la même mémoire avec des types ou des granularités différents. La propriétélengthde la vue donne le nombre d’éléments, etbyteLengthle nombre d’octets.
Écriture et lecture (opérations au niveau des octets)
Quand vous écrivez une valeur dans un TypedArray, les octets correspondants en mémoire sont mis à jour. Vous pouvez voir les modifications en lisant le même buffer avec une autre vue.
1// Demonstrate writing via one view and reading via another
2const buffer2 = new ArrayBuffer(4);
3const u8view = new Uint8Array(buffer2);
4const u32view = new Uint32Array(buffer2);
5
6u8view[0] = 0x78;
7u8view[1] = 0x56;
8u8view[2] = 0x34;
9u8view[3] = 0x12;
10
11console.log("Uint8 bytes:", Array.from(u8view)); // [120, 86, 52, 18]
12console.log("Uint32 value (platform endianness):", u32view[0]); // value depends on endianness
- Dans cet exemple, nous écrivons une séquence d’octets puis nous lisons la même zone comme un entier 32 bits. Notez que le résultat dépend de l’endianness (l’ordre des octets) de l’environnement d’exécution.
Endianness (ordre des octets) et DataView
DataView est utile si vous souhaitez gérer les problèmes d’endianness dépendants de l’environnement. DataView vous permet de spécifier l’endianness lors de la lecture et l’écriture.
1// Use DataView to read/write with explicit endianness control
2const b = new ArrayBuffer(4);
3const dv = new DataView(b);
4
5// write little-endian 32-bit integer
6dv.setUint32(0, 0x12345678, true);
7
8// read as little-endian and big-endian
9const little = dv.getUint32(0, true);
10const big = dv.getUint32(0, false);
11
12console.log("little-endian read:", little.toString(16)); // "12345678"
13console.log("big-endian read:", big.toString(16)); // different value
DataViewest un mécanisme pratique pour lire et écrire les octets en détail. Il prend en charge plusieurs types comme les entiers signés ou non signés et les flottants, et permet de spécifier explicitement l’endianness (l’ordre des octets), ce qui est très utile lors de l’implémentation de protocoles binaires.
Différence entre subarray et slice
La méthode subarray d’un TypedArray retourne une vue partageant le buffer d’origine, alors que slice retourne une nouvelle copie. Les performances et les effets de bord varient selon la méthode utilisée.
1const base = new Uint8Array([1, 2, 3, 4, 5]);
2
3const shared = base.subarray(1, 4); // shares underlying buffer
4const copied = base.slice(1, 4); // copies data
5
6shared[0] = 99;
7console.log("base after shared modification:", base); // shows change
8console.log("copied remains:", copied); // unaffected
- Si vous modifiez la vue partagée, le tableau original sera également modifié, ce qui peut entraîner des effets secondaires inattendus. Si vous souhaitez préserver en toute sécurité le tableau original, vous pouvez en créer une copie à l'avance en utilisant
slice().
Copier des buffers et conversion des types (conversion entre TypedArray)
Nous expliquerons comment copier des données entre TypedArray et comment coller des portions avec la méthode set.
1// Copy and convert between typed arrays
2const src = new Float32Array([1.5, 2.5, 3.5]);
3const dst = new Uint16Array(src.length);
4
5// Convert by mapping (explicit conversion)
6for (let i = 0; i < src.length; i++) {
7 dst[i] = Math.round(src[i]); // simple conversion rule
8}
9console.log("converted dst:", Array.from(dst)); // [2, 2, 4]
10
11// Using set to copy bytes (requires compatible underlying buffer or same element type)
12const src2 = new Uint8Array([10, 20, 30]);
13const dst2 = new Uint8Array(6);
14dst2.set(src2, 2); // copy src2 into dst2 starting at index 2
15console.log("dst2 after set:", Array.from(dst2)); // [0,0,10,20,30,0]
- Si les types d’éléments diffèrent, il faut convertir les valeurs (arrondir, vérifier la plage), pas simplement copier.
setpermet une copie rapide entreTypedArraydu même type d’éléments.
Exemple pratique : un parseur de protocole binaire (implémentation simple)
Voici un exemple simple de parseur lisant un format binaire fixe composé d’un type (1 octet), d’une longueur de données (2 octets) et d’une charge utile (payload) qui suit.
1// Simple binary message parser:
2// format: [type: uint8][length: uint16 BE][payload: length bytes]
3function parseMessages(buffer: ArrayBuffer) {
4 const dv = new DataView(buffer);
5 let offset = 0;
6 const messages: { type: number; payload: Uint8Array }[] = [];
7
8 while (offset + 3 <= dv.byteLength) {
9 const type = dv.getUint8(offset);
10 const length = dv.getUint16(offset + 1, false); // big-endian
11 offset += 3;
12 if (offset + length > dv.byteLength) break; // truncated
13 const payload = new Uint8Array(buffer, offset, length);
14 messages.push({ type, payload });
15 offset += length;
16 }
17
18 return messages;
19}
20
21// Example usage
22const buf = new ArrayBuffer(1 + 2 + 3 + 1 + 2 + 2); // two messages
23const dv = new DataView(buf);
24let off = 0;
25// first message: type=1, length=3, payload=[1,2,3]
26dv.setUint8(off, 1); dv.setUint16(off + 1, 3, false); off += 3;
27new Uint8Array(buf, off, 3).set([1, 2, 3]); off += 3;
28// second message: type=2, length=2, payload=[9,8]
29dv.setUint8(off, 2); dv.setUint16(off + 1, 2, false); off += 3;
30new Uint8Array(buf, off, 2).set([9, 8]);
31
32console.log(parseMessages(buf));- Dans cet exemple, l'en-tête est lu à l'aide de
DataView, et la portion de données utiles (payload) est créée avecUint8Array. L’endianness et la vérification de la longueur du buffer sont importantes.
Web API et TypedArray (exemple : téléchargement de données binaires)
Ceci est un exemple classique de manipulation d’un ArrayBuffer obtenu par une requête réseau avec TypedArray.
1// Example of fetching binary and mapping to typed array
2async function fetchBinary(url: string) {
3 const res = await fetch(url);
4 const ab = await res.arrayBuffer();
5 const view = new Uint8Array(ab);
6 // process view...
7 console.log("received bytes:", view.length);
8 return view;
9}
10
11// Usage (call in async context)
12// fetchBinary("/path/to/file.bin");
- Vous pouvez passer directement l’
ArrayBufferobtenu viaResponse.arrayBuffer()à unTypedArray. On l’utilise pour les images, l’audio ou les protocoles binaires personnalisés.
Astuces de performances et pièges courants
Voici quelques conseils de performance et pièges fréquents à connaître lors de l'utilisation des TypedArray :.
-
Évitez les copies inutiles Pour traiter efficacement de grandes quantités de données, réduisez les copies inutiles en créant des vues partielles avec
subarrayou en partageant le mêmeArrayBufferentre plusieurs vues. -
Attention à l’endianness Pour la communication réseau ou les formats de fichiers, l’ordre des données (endianness) est souvent spécifié. Utiliser
DataViewvous permet de spécifier explicitement l’endianness à la lecture/écriture, ce qui évite des interprétations erronées. -
Attention aux plages de valeurs de chaque type Par exemple,
Uint8ne peut représenter que des valeurs de 0 à 255. Si vous saisissez une valeur négative, une troncature ou un dépassement de valeur peut se produire ; il est donc recommandé de définir des règles de conversion selon les besoins. -
Attention à la pression sur le ramasse-miettes (garbage collection) Recréer fréquemment de grands
ArrayBufferaugmente la charge de la gestion de la mémoire. Dans les situations où les performances sont critiques, vous pouvez envisager de concevoir le code afin de réutiliser autant que possible les tampons (buffers) existants.
Résumé
TypedArray est un mécanisme pour traiter les données binaires de manière rapide et efficace. En combinant l'ArrayBuffer, qui réserve une zone d’octets de taille fixe, avec les TypedArray ou DataView qui lisent et écrivent les contenus en types spécifiques, vous pouvez réaliser des opérations binaires flexibles. Selon votre cas d'utilisation, vous pouvez choisir d'utiliser subarray/slice ou DataView, et concevoir votre implémentation en prêtant attention à l'endianness et aux copies.
Vous pouvez suivre l'article ci-dessus avec Visual Studio Code sur notre chaîne YouTube. Veuillez également consulter la chaîne YouTube.