Avant d'utiliser JavaScript, j'étais déjà assez familier avec C, C++ et C#. Comme beaucoup de développeurs C/C++, ma première impression de JavaScript n’a pas été bonne. Cet article présente principalement l'évolution et l'analyse des performances des tableaux JavaScript. Cet article parle davantage de la mémoire, de l'optimisation, des différences de syntaxe, des performances et des évolutions récentes. Les amis dans le besoin peuvent s'y référer, j'espère que cela pourra aider tout le monde.
Array est l'une des principales raisons. Les tableaux JavaScript ne sont pas contigus et sont implémentés comme des cartes de hachage ou des dictionnaires. J'ai l'impression que c'est un peu un langage de niveau B et que l'implémentation du tableau est tout simplement inappropriée. Depuis lors, JavaScript et ma compréhension de celui-ci ont beaucoup changé.
Pourquoi les tableaux JavaScript ne sont pas de vrais tableaux
Avant de parler de JavaScript, parlons d'abord de ce qu'est un tableau.
Un tableau est une séquence contiguë d'emplacements mémoire utilisés pour contenir une certaine valeur. Il est important de noter l'accent mis sur « continu » (ou contigu).
La figure ci-dessus montre comment les tableaux sont stockés en mémoire. Ce tableau contient 4 éléments, chaque élément fait 4 octets. Au total, il occupe 16 octets de zone mémoire.
Supposons que nous déclarions tinyInt arr[4];, l'adresse de la zone mémoire allouée commence à 1201. Une fois que vous avez besoin de lire arr[2], il vous suffit d'obtenir l'adresse de arr[2] via des calculs mathématiques. Pour calculer 1201 + (2 X 4), commencez simplement à lire directement à partir de 1209.
Les données en JavaScript sont une carte de hachage, qui peut être implémentée en utilisant différentes structures de données, telles que des listes chaînées. Ainsi, si vous déclarez un tableau en JavaScript var arr = new Array(4), l'ordinateur générera une structure similaire à celle présentée ci-dessus. Si le programme a besoin de lire arr[2], il doit parcourir l'adressage à partir de 1201.
Les différences entre les tableaux JavaScript rapides ci-dessus et les tableaux réels. De toute évidence, les calculs mathématiques sont plus rapides que le parcours d'une liste chaînée. Cela est particulièrement vrai pour les tableaux longs.
L'évolution des tableaux JavaScript
Je me demande si vous vous souvenez de l'époque où nous enviions tant l'ordinateur de 256 Mo que nos amis achetaient ? Aujourd'hui, 8 Go de RAM sont partout.
De même, le langage JavaScript a également beaucoup évolué. De V8 et SpiderMonkey à TC39 et au nombre croissant d'utilisateurs Web, d'énormes efforts ont fait de JavaScript une nécessité de classe mondiale. Une fois que vous disposez d’une énorme base d’utilisateurs, l’amélioration des performances est naturellement une exigence essentielle.
En fait, les moteurs JavaScript modernes alloueront de la mémoire contiguë aux tableaux - si le tableau est homogène (tous les éléments sont du même type). Un bon programmeur veillera toujours à ce que le tableau soit homogène afin que le JIT (compilateur juste à temps) puisse lire les éléments à l'aide de calculs de style compilateur C.
Cependant, une fois que vous souhaitez insérer un élément d'un autre type dans un tableau homogène, le JIT déconstruira l'intégralité du tableau et le recréera à l'ancienne.
Donc, si votre code n'est pas trop mauvais, les objets JavaScript Array restent de véritables tableaux en coulisses, ce qui est extrêmement important pour les développeurs JS modernes.
De plus, les baies ont davantage évolué après ES2015/ES6. TC39 a décidé d'introduire des tableaux typés (Typed Arrays), nous avons donc ArrayBuffer.
ArrayBuffer fournit une mémoire continue que nous pouvons opérer à volonté. Cependant, exploiter directement la mémoire est encore trop compliqué et de faible niveau. Il existe donc une vue qui gère ArrayBuffer. Quelques vues sont déjà disponibles et d'autres seront ajoutées à l'avenir.
var buffer = new ArrayBuffer(8); var view = new Int32Array(buffer); view[0] = 100;
Des tableaux typés performants et efficaces ont été introduits après WebGL. Les travailleurs WebGL rencontrent un énorme problème de performances, à savoir comment gérer efficacement les données binaires. Vous pouvez également utiliser SharedArrayBuffer pour partager des données entre plusieurs processus Web Worker afin d'améliorer les performances.
Passer d'une simple hash map à maintenant un SharedArrayBuffer, c'est plutôt cool, non ?
Tableaux à l'ancienne vs tableaux typés : performances
Nous avons déjà discuté de l'évolution des tableaux JavaScript, testons maintenant les avantages que les tableaux modernes peuvent nous apporter. Voici quelques résultats de micro-tests que j'ai exécutés sur un Mac en utilisant Node.js 8.4.0.
Tableau à l'ancienne : insérer
var LIMIT = 10000000; var arr = new Array(LIMIT); console.time("Array insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.timeEnd("Array insertion time");
temps : 55 ms
Typed Array:插入 var LIMIT = 10000000; var buffer = new ArrayBuffer(LIMIT * 4); var arr = new Int32Array(buffer); console.time("ArrayBuffer insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.timeEnd("ArrayBuffer insertion time");
temps : 52 ms
Enrouler, qu'est-ce que je vois ? Les tableaux à l'ancienne et ArrayBuffer sont-ils également performants ? Non non non. N'oubliez pas que, comme mentionné précédemment, les compilateurs modernes sont suffisamment intelligents pour convertir en interne des tableaux traditionnels du même type d'élément en tableaux contigus en mémoire. C'est exactement le cas du premier exemple. Malgré l'utilisation du nouveau tableau (LIMIT), le tableau existe toujours en tant que tableau moderne.
Modifiez ensuite le premier exemple et changez le tableau en un tableau hétérogène (les types d'éléments ne sont pas complètement cohérents) pour voir s'il y a une différence de performances.
旧式数组:插入(异构) var LIMIT = 10000000; var arr = new Array(LIMIT); arr.push({a: 22}); console.time("Array insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.timeEnd("Array insertion time");
Durée prise : 1207 ms
Le changement se produit à la ligne 3, en ajoutant une instruction pour changer le tableau en un type hétérogène. Le reste du code reste inchangé. La différence de performances apparaît, 22 fois plus lentement.
Tableau à l'ancienne : Lecture
var LIMIT = 10000000; var arr = new Array(LIMIT); arr.push({a: 22}); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } var p; console.time("Array read time"); for (var i = 0; i < LIMIT; i++) { //arr[i] = i; p = arr[i]; } console.timeEnd("Array read time");
temps : 196 ms
Typed Array:读取 var LIMIT = 10000000; var buffer = new ArrayBuffer(LIMIT * 4); var arr = new Int32Array(buffer); console.time("ArrayBuffer insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.time("ArrayBuffer read time"); for (var i = 0; i < LIMIT; i++) { var p = arr[i]; } console.timeEnd("ArrayBuffer read time");
temps : 27 ms
Conclusion
L'introduction des tableaux typés est une étape importante dans le développement de JavaScript. Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, ce sont des vues de tableau typées, utilisant l'endianité native (identique à la native). Nous pouvons également créer des fenêtres de vue personnalisées à l'aide de DataView. Espérons qu'il y aura plus de bibliothèques DataView qui nous aideront à manipuler facilement les ArrayBuffers à l'avenir.
L'évolution des tableaux JavaScript est très sympa. Ils sont désormais suffisamment rapides, efficaces, robustes et intelligents en matière d’allocation de mémoire.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!