Est-ce que j'ai atteint les limites de la taille des objets que JavaScript peut gérer dans mon navigateur?

J'implie un tableau étendu dans les balises <script> dans mon HTML, comme ceci (rien d'étonnant):

 <script> var largeArray = [/* lots of stuff in here */]; </script> 

Dans cet exemple particulier, le tableau a 210 000 éléments. C'est bien au-dessous du maximum théorique de 2 31 – par 4 ordres de grandeur . Voici la partie amusante: si je sauvegarde la source JS pour le tableau dans un fichier, ce fichier est> 44 méga-octets (46 573 315 octets, pour être exact).

Si vous voulez voir par vous-même, vous pouvez le télécharger depuis GitHub . (Toutes les données existantes sont en conserve, beaucoup de celles-ci sont répétées. Ce ne sera pas le cas dans la production).

Maintenant, je ne suis vraiment pas préoccupé de servir autant de données. Mon serveur gzips ses réponses, donc il ne prend vraiment pas tant de temps à obtenir les données sur le fil. Cependant, il existe une tendance vraiment méchante pour la page, une fois chargée, pour bloquer le navigateur. Je ne teste pas du tout dans IE (c'est un outil interne). Mes principales cibles sont Chrome 8 et Firefox 3.6.

Dans Firefox, je peux voir une erreur raisonnablement utile dans la console:

Error: script stack space quota is exhausted

Dans Chrome, je reçois simplement la page triste:

Entrez la description de l'image ici

Couper à la poursuite, déjà

  • Est-ce vraiment de très nombreuses données pour nos navigateurs modernes à haute performance?
  • Y a-t-il quelque chose que je puisse faire * pour gérer gracieusement ces nombreuses données?

Par ailleurs, j'ai été en mesure de faire fonctionner ce travail (lisez: ne bloquez pas l'onglet) activé et désactivé sur Chrome. Je pensais vraiment que Chrome, au moins, était fait de choses plus difficiles, mais je me sentais mal …


Modifier 1

@Crayon: Je ne cherchais pas à justifier pourquoi j'aimerais jeter toutes ces données dans le navigateur à la fois. Version courte: soit je résolve ce problème (certes pas si facile), soit je dois résoudre un tas d'autres problèmes. Je choisis l'approche plus simple pour l'instant.

@various: en ce moment, je ne cherche pas particulièrement à trouver des moyens de réduire réellement le nombre d'éléments dans le tableau. Je sais que je pourrais mettre en œuvre la pagination d'Ajax ou ce qui-a-toi, mais cela me présente ses propres problèmes.

@Phrogz: chaque élément ressemble à ceci:

 {dateTime:new Date(1296176400000), terminalId:'terminal999', 'General___BuildVersion':'10.05a_V110119_Beta', 'SSM___ExtId':26680, 'MD_CDMA_NETLOADER_NO_BCAST___Valid':'false', 'MD_CDMA_NETLOADER_NO_BCAST___PngAttempt':0} 

@Will: mais j'ai un ordinateur avec un processeur 4-core, 6 gigaoctets de RAM, plus d'un demi-térapete d'espace disque … et je ne demande même pas au navigateur de le faire rapidement – je demande juste Pour qu'il fonctionne du tout!


Modifier 2

Mission accomplie!

Avec les suggestions de Juan ainsi que Guffa , j'ai pu faire fonctionner ça! Il semblerait que le problème était juste d' analyser le code source, ne fonctionnant pas avec lui en mémoire.

Pour résumer le commentaire du bourbier sur la réponse de Juan: j'ai dû diviser mon grand tableau en une série de plus petits, puis Array#concat() eux, mais cela ne suffisait pas. J'ai également dû les mettre dans des déclarations distinctes var . Comme ça:

 var arr0 = [...]; var arr1 = [...]; var arr2 = [...]; /* ... */ var bigArray = arr0.concat(arr1, arr2, ...); 

A tous ceux qui ont contribué à résoudre ceci: merci. Le premier tour est sur moi!


* Autre que l'évidence: envoyer moins de données au navigateur

Voici ce que j'essayerais: vous avez dit que c'est un fichier de 44 Mo. Cela prend certainement plus de 44 Mo de mémoire, je suppose que cela prend beaucoup plus de 44 Mo de RAM, peut-être un demi-concert. Pourriez-vous simplement réduire les données jusqu'à ce que le navigateur ne se bloque pas et voir la quantité de mémoire utilisée par le navigateur?

Même les applications qui fonctionnent uniquement sur le serveur seraient bien servies pour ne pas lire un fichier de 44 Mo et le garder en mémoire. Cela dit, je crois que le navigateur devrait pouvoir le gérer, alors laissez-moi faire quelques tests.

(Utilisation de Windows 7, 4 Go de mémoire)

Premier test J'ai coupé le tableau en deux et il n'y a eu aucun problème, utilise 80 Mo, pas de crash

Deuxième test Je divise le tableau en deux tableaux distincts, mais contient toujours toutes les données, utilise 160Mb, pas de crash

Troisième test Puisque Firefox a dit qu'il avait manqué de pile, le problème est probablement qu'il ne peut pas analyser le tableau à la fois. J'ai créé deux tableaux distincts, arr1, arr2 puis arr3 = arr1.concat (arr2); Il a fonctionné correctement et utilise seulement un peu plus de mémoire, environ 165 Mo.

Quatrième test Je crée 7 de ces tableaux (22 Mo chacun) et je les concède pour tester les limites du navigateur. Cela prend environ 10 secondes pour que la page termine son chargement. La mémoire augmente jusqu'à 1,3 Go, puis elle remonte à 500 Mo. Donc oui, chrome peut le gérer. Il ne peut tout simplement pas analyser tout à la fois car il utilise une sorte de récurrence comme le remarque le message d'erreur de la console.

Réponse Créez des tableaux distincts (moins de 20 Mo chacun) puis concattez-les. Chaque tableau doit être sur sa propre instruction var, au lieu de faire plusieurs déclarations avec une seule var.

Je considérerais toujours chercher uniquement la partie nécessaire, cela pourrait rendre le navigateur lent. Toutefois, si c'est une tâche interne, cela devrait être bien.

Dernier point: vous n'êtes pas au niveau de la mémoire maximale, juste des niveaux d'analyse max.

Oui, c'est trop demander un navigateur.

Cette quantité de données serait managable si elle était déjà des données, mais ce ne sont pas encore des données. Considérez que le navigateur doit analyser cet énorme bloc de code source tout en vérifiant que la syntaxe s'ajoute à tout cela. Une fois analysé dans le code valide, le code doit être exécuté pour produire le tableau réel.

Ainsi, toutes les données existent dans (au moins) deux ou trois versions à la fois, chacune avec une certaine quantité de frais généraux. Comme le tableau literal est une déclaration unique, chaque étape devra inclure toutes les données.

La division des données en plusieurs tableaux plus petits pourrait faciliter le navigateur.

Avez-vous vraiment besoin de toutes les données? Vous ne pouvez pas diffuser les données actuellement nécessaires à l'aide d'AJAX? À l'instar de Google Maps – vous ne pouvez pas intégrer toutes les données de la carte dans la mémoire du navigateur, elles affichent uniquement la partie que vous voyez actuellement.

Rappelez-vous que 40 mégawatts de données dures peuvent être gonflés à beaucoup plus dans la représentation interne du navigateur. Par exemple, l'interpréteur JS peut utiliser hashtable pour implémenter le tableau, ce qui ajouterait des frais généraux additionnels. De plus, je m'attends à ce que les navigateurs stockent le code source et la mémoire JS, ce qui seul double la quantité de données.

JS est conçu pour fournir une interaction UI côté client, ne gère pas les charges de données.

MODIFIER:

Btw, pensez-vous vraiment que les utilisateurs voudront télécharger 40 mégaoctets de code? Il y a encore beaucoup d'utilisateurs avec moins d'accès Internet haut débit. Et l'exécution du script sera suspendue jusqu'à ce que toutes les données soient téléchargées.

EDIT2:

J'ai regardé les données. Ce tableau sera définitivement représenté comme hashtable. En outre, beaucoup d'objets sont des objets, ce qui nécessitera un suivi de référence … c'est une mémoire supplémentaire.

Je suppose que la performance serait meilleure si c'était un vecteur simple de données primitives.

EDIT3: les données pourraient certainement être simplifiées. La majeure partie est en train de répéter des chaînes, qui peuvent être encodées en quelque sorte comme entiers ou quelque chose. De plus, mon Opera a du mal à afficher le texte, encore moins à l'interpréter.

EDIT4: Oubliez les objets DateTime ! Utilisez les horodatages ou les chaînes de l'époque unix, mais pas les objets!

EDIT5: Votre processeur n'a pas d'importance car JS est simple. Et votre RAM n'a pas d'importance non plus, la plupart des navigateurs sont 32 bits, donc ils ne peuvent pas utiliser beaucoup de mémoire.

EDIT6: Essayez de modifier les indices de tableau en entiers séquentiels (0, 1, 2, 3 …). Cela pourrait permettre au navigateur d'utiliser une structure de données de tableau plus efficace. Vous pouvez utiliser des constantes pour accéder efficacement aux éléments du tableau. Cela réduira la taille du tableau par un gros morceau.

Essayez de récupérer les données avec Ajax en tant que page JSON. Je ne connais pas la taille exacte, mais j'ai pu tirer de grandes quantités de données dans Google Chrome de cette façon.

Utilisez un chargement paresseux. Avoir des conseils sur les données et l'obtenir lorsque l'utilisateur le demande.

Cette technique est utilisée dans divers endroits pour gérer des millions d'enregistrements de données.

[Modifier]

J'ai trouvé ce que je cherchais. Défilement virtuel dans jqgrid . Ce sont 500k enregistrements étant paresseux.

J'essayerais de l'avoir comme une grande chaîne avec séparateur entre chaque "élément" puis utilisez split , quelque chose comme:

 var largeString = "item1,item2,......."; var largeArray = largeString.split(","); 

Espérons que la chaîne n'étendra pas la pile si rapidement.

Edit: pour le tester, j'ai créé un tableau fictif avec 200 000 éléments simples (chaque numéro d'article un) et Chrome l'a chargé en un instant. 2 000 000 d'articles? Un couple de secondes, mais pas de collision. 6,000,000 items array (50 Mo de fichier) ont généré une charge de Chrome pendant environ 10 secondes mais toujours, pas de collision dans les deux sens.

Donc, cela m'amène à croire que le problème n'est pas avec le tableau lui-même, mais plutôt son contenu … optimisez le contenu à des objets simples, puis analysez-les «à la volée» et cela devrait fonctionner.