web-dev-qa-db-fra.com

Où utiliser ArrayBuffer vs tableau typé en JavaScript?

Je passe de Node.js à l'environnement du navigateur, et je suis toujours confus entre ArrayBuffer et les tableaux typés (tels que Uint8Array).

Je ne sais pas où utiliser les tableaux typés et où utiliser directement ArrayBuffer. Ce n'est pas difficile de convertir l'un en l'autre et vice versa, mais lequel utiliser quand?

Par exemple, lorsque je crée un objet qui représentera un bloc de données dans mon code, devrait-il être ArrayBuffer ou Uint8Array? De quoi cela dépend-il?

Ou: dois-je plutôt retourner ArrayBuffer à partir de mes fonctions (par exemple, pour une API externe) ou des tableaux typés?

Notez que je peux google comment ajouter exactement des éléments, etc. à ces tableaux tapés; ce qui me manque, c'est un petit guide général quoi utiliser où. Surtout lors du passage du tampon du nœud.

29
Karel Bílek

Concepts

ArrayBuffer s représente un tableau d'octets dans la mémoire physique. Un ArrayBuffer est le stockage réel des octets mais est rarement utilisé directement - en fait, vous n'avez pas accès au contenu de lecture d'ArrayBuffer directement et ne pouvez que lui transmettre une référence. Ils sont par contre utilisés pour les transferts de données binaires entre serveur et client, ou depuis le système de fichiers de l'utilisateur via Blobs.

ArrayBuffer byte array in memory
Tableau d'octets ArrayBuffer en mémoire - chaque index est égal à un octet. ArrayBuffer est aligné en mémoire.

Pour lire le contenu d'un ArrayBuffer, vous devez utiliser une vue . Celui-ci se trouve en haut et offre une "api" pour accéder aux octets par différents types de largeur, ou arbitrairement.

Vues dépendantes de la largeur

Les différentes vues sont utilisées en fonction de vos besoins. Si vous avez seulement besoin de lire les valeurs d'octets, par exemple. valeurs signées entre -128 et 127 -ou- valeurs non signées entre 0 et 255, vous utiliseriez Int8Array ou Uint8Array. Notez que leurs noms sont un peu "trompeurs" car ce sont des vues et non des tableaux, et ne font référence qu'à l'ArrayBuffer sous-jacent.

De même, vous avez des vues pour Int8Array , int8Array , int8ClampedArray , Int16Array , int16Array , Int32Array , int3Array , Float32Array et Float64Array .

À l'exception de * int8Arrays, les autres sont soumis à une certaine exigence de taille ArrayBuffer. Par exemple, une vue Uint32Array doit être placée au-dessus d'un ArrayBuffer divisible par quatre, sinon elle génère une erreur. * Les vues int 16 nécessiteraient une limite de deux octets.

Ce n'est généralement pas un problème car vous pouvez spécifier le nombre d'index en utilisant directement le constructeur de la vue et un ArrayBuffer correspondant sera créé automatiquement pour qu'il remplisse ces conditions.

Et comme ArrayBuffer est un tableau d'octets, une vue * int16 en lit deux octets - ou, un index = deux octets, * int32 quatre, ou un index = quatre octets, etc.

La principale différence entre Uint8Array et Uint8ClampedArray est que les valeurs en dehors de la plage sont sujettes à modulo (par exemple 256 devient 0) avec les tableaux ordinaires. Dans le tableau de serrage, les valeurs sont celles suggérées à la place (256 devient 255).

*int16 view
Vues Int16/Uint16 - chaque index représente deux octets et est aligné en mémoire.

*int32 view
Vues Int32/Uint32 et Float32 - chaque index représente quatre octets et est aligné en mémoire.

Float64 view
Vue Float64 - chaque index représente huit octets et est aligné en mémoire.

DataView pour plus de flexibilité

Ensuite, il y a le DataView. Ceci est destiné aux scénarios où vous avez besoin d'un ArrayBuffer flexible et devez lire des largeurs variables et à partir de positions dans le tampon qui ne sont pas nécessairement alignées en largeur ou en mémoire.

Par exemple, un index * int32 pointera toujours vers un emplacement mémoire divisible par quatre. Un DataView, d'autre part, peut lire un Uint32 à partir de la position 5, par exemple, et prendra en charge toutes les étapes nécessaires en interne (décalage de bits, masquage, etc.), mais au prix d'une minuscule surcharge.

Une autre différence est qu'un DataView n'utilise pas d'index mais des positions d'octets absolues pour les données qu'il représente, et il est livré avec ses propres méthodes pour lire ou écrire différentes largeurs de/vers n'importe quelle position.

DataView
DataView - peut lire depuis n'importe quelle position et n'importe quelle largeur.

Dans d'autres cas, vous pouvez utiliser plusieurs vues différentes référençant le même ArrayBuffer sous-jacent.

Il n'y a actuellement pas de vues 64 bits pour les nombres entiers, mais semble être proposé pour ES8 .

SharedArrayBuffers

Il est également utile de mentionner le nouveau SharedArrayBuffers qui peut être utilisé par les travailleurs Web.

Vous pouvez (et pouvez toujours) utiliser objets transférables dans le passé dans certains navigateurs, mais SharedArrayBuffers est plus efficace dans le sens où la mémoire reste la même, seules les informations à ce sujet sont transférées. SharedArrayBuffers ne peut pas se détacher comme le peuvent les ArrayBuffers.

Domaines d'utilisation et d'utilisation

Les tableaux typés sont bons pour stocker des valeurs numériques spécifiques et sont rapides. Les bitmaps sont un candidat typique pour les tableaux typés (par exemple, canvas 2D/WebGL).

Le traitement intensif des données à l'intérieur des travailleurs Web est une autre utilisation, etc. J'ai déjà mentionné le transfert binaire entre le client et le serveur ou le système de fichiers.

Les DataViews sont parfaits pour analyser ou créer des fichiers binaires et des formats de fichiers.

Les tableaux typés sont un excellent moyen de compresser des données binaires pour les envoyer sur le net, au serveur ou via des sockets Web et des choses comme des canaux de données pour WebRTC.

Si vous traitez l'enregistrement audio, vidéo, canevas ou multimédia, il est souvent impossible d'utiliser des tableaux typés.

Les clés pour utiliser des tableaux tapés sont les performances et la mémoire. Ils sont le plus souvent utilisés dans des scénarios spéciaux, mais il n'y a rien de mal à les utiliser dans des cas ordinaires lorsque vous n'avez besoin que de stocker des valeurs numériques (ou des chaînes utf-8, des vecteurs de chiffrement, etc.). Ils sont rapides et ont une faible empreinte mémoire.

Précautions

Il y a quelques précautions à prendre en compte:

Ordre des octets

Certaines précautions doivent être prises en ce qui concerne l'ordre des octets. Les tableaux typés reflètent toujours l'architecture CPU sous laquelle ils fonctionnent, c'est-à-dire. petit-endian ou big-endian. La plupart des systèmes grand public sont peu endiens, mais lorsque vous utilisez des tableaux * int16 et * int32, vous devez porter une attention particulière à l'ordre des octets. DataView peut également aider avec cette partie, mais n'est pas toujours un bon choix si les performances sont importantes.

L'ordre des octets est également important lors de la réception de données du serveur. Ils sont généralement toujours au format big-endian (AKA "network order"). Pour l'analyse des formats de fichiers, la même chose s'applique.

Encodage du nombre à virgule flottante

Float32/Float64 lit et écrit les nombres encodés au format IEEE-754 . C'est également quelque chose à savoir si plusieurs vues sont utilisées pour le même tampon.

Prise en charge de plusieurs navigateurs

La plupart des navigateurs prennent en charge les tableaux typés de nos jours. Si vous devez gérer des navigateurs plus anciens, vous devez revenir à IE9 ou à des navigateurs mobiles plus anciens pour ne pas pouvoir les utiliser.

Safari n'est pas particulièrement optimisé en ce qui concerne leurs performances, mais les autres avantages sont là. La version 5.1 ne prend pas en charge Float64.

Les appareils mobiles ont leurs propres limitations matérielles, mais en général: les tableaux tapés sont sûrs à utiliser. Pour des cas particuliers, il existe un polyfill .

59
user1693593