web-dev-qa-db-fra.com

Existe-t-il un moyen de créer des éléments DOM dans Web Worker?

Contexte: J'ai une application Web qui traite et affiche d’énormes fichiers journaux. Leur longueur ne dépasse généralement pas 100 000 lignes, mais peut atteindre 4 millions de lignes ou plus. Pour pouvoir faire défiler ce fichier journal (à l'initiative de l'utilisateur et via JavaScript) et filtrer les lignes avec des performances décentes, je crée un élément DOM pour chaque ligne dès l'arrivée des données (en JSON via ajax). J'ai trouvé cela meilleur pour la performance que la construction du code HTML dans le back-end. Ensuite, j'enregistre les éléments dans un tableau et ne montre que les lignes visibles.

Pour un maximum de 100 000 lignes, cela ne prend que quelques secondes environ, mais toute opération supplémentaire prend jusqu'à une minute pour 500 000 lignes (téléchargement non compris). Je voulais améliorer encore plus les performances. J'ai donc essayé d'utiliser HTML5 Web Workers. Le problème maintenant est que je ne peux pas créer d'éléments dans un Web Worker, même en dehors du DOM. J'ai donc fini par ne faire que la conversion JSON en HTML dans les Web Workers et envoyer le résultat au thread principal. Là, il est créé et stocké dans un tableau. Malheureusement, cela a aggravé la performance et cela prend maintenant au moins 30 secondes de plus.

Question: Alors, y a-t-il un moyen, dont je ne suis pas au courant, de créer des éléments DOM, en dehors de l'arborescence DOM, dans un Web Worker? Si non pourquoi pas Il me semble que cela ne peut pas créer de problèmes de concurrence, car la création des éléments pourrait se faire en parallèle sans problèmes.

40
Joren Van Severen

Bon, j'ai fait quelques recherches supplémentaires avec les informations fournies par @Bergi et j'ai trouvé la discussion suivante sur la liste de diffusion du W3C:

http://w3-org.9356.n7.nabble.com/Limited-DOM-in-Web-Workers-td44284.html

Et l'extrait qui explique pourquoi il n'y a pas d'accès à l'analyseur XML ou à l'analyseur DOM dans Web Worker:

Vous supposez qu'aucun code d'implémentation DOM n'utilise aucune sorte des objets non-DOM, jamais, ou que si c'est le cas, ces objets sont entièrement threadsafe. Ce n'est tout simplement pas le cas, du moins à Gecko. 

Dans ce cas, le problème n’est pas le même objet DOM que nous abordons plusieurs threads. Le problème est deux objets DOM sur des threads différents les deux touchant un troisième objet global. 

Par exemple, l'analyseur XML doit effectuer certaines tâches que Gecko peut effectuer ne peut être effectué que sur le fil principal (chargement de la DTD, au hasard; il y en a quelques-uns que j'ai vus auparavant mais dont je ne me rappelle pas au hasard).

Toutefois, il existe également une solution de contournement mentionnée, qui utilise une implémentation tierce des analyseurs, dont jsdom est un exemple. Avec cela, vous avez même accès à votre propre document séparé.

16
Joren Van Severen

Donc, y a-t-il un moyen, dont je ne suis pas au courant, de créer des éléments DOM, en dehors de l'arborescence DOM, dans un Web Worker?

Non.

Pourquoi pas? Il me semble que cela ne peut pas créer de problèmes de concurrence, car la création des éléments pourrait se faire en parallèle sans problèmes.

Pas pour les créer, vous avez raison. Mais pour les annexer à la variable document principale - ils auraient besoin d'être envoyés dans une mémoire différente (comme c'est le cas pour les blobs) afin qu'ils ne soient plus accessibles par le travailleur. Cependant, il n'y a absolument aucune gestion de document disponible dans WebWorkers .

Je crée un élément DOM pour chaque ligne dès l'arrivée des données (en JSON via ajax). Ensuite, j'enregistre les éléments dans un tableau et ne montre que les lignes visibles.

Construire plus de 500k éléments DOM est la lourde tâche. Essayez de créer des éléments DOM uniquement pour les lignes visibles. Pour améliorer les performances et afficher plus rapidement les premières lignes, vous pouvez également diviser leur traitement en unités plus petites et utiliser des délais d'attente entre les deux. See Comment empêcher une boucle Javascript intense de geler le navigateur

10
Bergi

Vous devez comprendre la nature d'un travailleur web. Programmer avec des threads est difficile , surtout si vous partagez de la mémoire; des choses étranges peuvent arriver. JavaScript n'est pas équipé pour traiter tout type d'entrelacement de type fil.

L'approche des webworkers est qu'il n'y a pas de mémoire partagée . Cela conduit évidemment à la conclusion que vous ne pouvez pas accéder au DOM.

4
Halcyon

Il n'y a pas de moyen direct d'accéder au DOM par le biais de Web Workers. J'ai récemment publié @ cycle/sandbox, il s'agit toujours d'un WIP, mais cela prouve qu'avec l'architecture Cycle JS, il est assez simple de déclarer le comportement de l'interface utilisateur dans Web Worker. Le DOM réel n’est touché que dans le fil principal, mais les écouteurs d’événement et les mises à jour du DOM sont déclarés indirectement dans l’ouvrier et un objet événement synthétisé est envoyé lorsque quelque chose se produit sur ces écouteurs. De plus, il est facile de monter ces composants de cycle normaux côte à côte, avec des composants de cycle bacs à sable.

http://github.com/aronallen/-cycle-sandbox/

4
Aron Allen

Je ne vois aucune raison pour laquelle vous ne pouvez pas construire de chaînes HTML à l'aide de travailleurs Web. Mais je ne pense pas non plus que les performances augmenteraient considérablement.

Ce n'est pas lié aux Web-Workers, mais au problème que vous essayez de résoudre. Voici quelque chose qui pourrait aider à accélérer les choses:

  1. Utilisez DocumentFragments. Ajoutez-leur des éléments au fur et à mesure que les données arrivent et ajoutez les fragments au DOM à intervalles réguliers (comme une fois par seconde). De cette façon, vous n'avez pas à toucher le DOM (et à effectuer un rafraîchissement) chaque fois qu'une ligne de texte est chargée.

  2. Effectuez le chargement en arrière-plan et n'analysez les lignes que lorsque l'utilisateur appuie sur le bas de la zone de défilement.

2
posit labs

Selon https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers il n’existe malheureusement pas d’accès au DOM depuis un Web.

1
Strille

Vous avez quelques anti-modèles dans votre conception:

  1. La création d'un objet DOM entraîne une surcharge considérable et vous créez potentiellement des millions d'entre eux à la fois.
  2. Essayer de faire gérer le DOM par un travailleur Web est exactement ce que les travailleurs Web Sont pas pour. Ils font tout le reste pour que la boucle d'événements DOM reste sensible.

Vous pouvez utiliser un modèle de curseur pour faire défiler/ arbitrairement volumineux ensembles de données.

  1. DOM envoie un message au travailleur avec la position de départ et le nombre de lignes demandées (curseur). 
  2. Le travailleur Web accède de manière aléatoire aux journaux et affiche les lignes récupérées (données de curseur).
  3. DOM met à jour un élément avec l'événement de réponse du curseur asynchrone.

De cette façon, les tâches lourdes sont effectuées par le travailleur, dont la boucle d'événements est bloquée lors de l'extraction au lieu du DOM, ce qui donne à de heureux utilisateurs non bloqués émerveillés par la fluidité de toutes vos animations.

1
Dominic Cerisano

Donc, vous ne pouvez pas créer directement de DOM dans un webworker - cependant, il peut exister une autre option pour effectuer une bonne partie de votre traitement en dehors du thread principal.

Découvrez ce jsPerf que je viens de créer: http://jsperf.com/dom-construction-obj-vs-str

Essentiellement, vous pourriez émettre des POJSOs qui ont toutes les mêmes valeurs que vous obtenez d'un DOM et le convertir en objets DOM après réception du message (c'est ce que vous faites lorsque vous récupérez du HTML, après tout; Les POJSO ne sont que des temps d’enregistrement moindres car ils ne nécessitent pas de traitement de chaîne supplémentaire. De cette façon, vous pouvez même faire des choses comme émettre des écouteurs d’événement et autres (par exemple en préfixant le nom de l’événement avec «!» Et en faisant correspondre la valeur à un argument de vue fourni par un modèle).

En attendant, sans l'analyseur DOM disponible, vous aurez besoin de votre propre logiciel pour convertir un modèle à la demande ou pour en compiler un dans un format rapide.

0
Fordi

Non, vous ne pouvez pas créer d'éléments DOM dans un outil de traitement Web, mais vous pouvez créer une fonction qui accepte le message de publication de cet outil de traitement Web. Cette variable does crée les éléments DOM. Je pense que la daigne que vous recherchez s'appelle le «mandrin de tableau». Et vous auriez besoin de mélanger cela avec le modèle de conception de Web worker.

0
user316264