Traitement asynchrone - Javascript/Node.js - Programmation
Marsh Posté le 01-06-2020 à 16:18:15
Exemple de ce que j'ai tenté :
Code :
|
Cela semble pas mal, mais l'affichage de l'élément "loading" ne se fait pas...
EDIT : donc dans ce cas là j'ai dans la console au fur et à mesure, "start" puis "step 1" puis "end" et aucun affichage du loader entre "start" et "step 1".
Marsh Posté le 01-06-2020 à 16:39:38
Ok je crois que le problème est lié au DOM et non vraiment à l'asynchronité.
Marsh Posté le 01-06-2020 à 17:17:31
Réglé comme ça :
Code :
|
Si quelqu'un a plus propre, qu'il n'hésite pas surtout.
EDIT : on oublie, en fonction des propriétés CSS attribuées ça bug, en fonction de si ça passe en cache ou non ça bug. Il semblerait que ce soit mission impossible...
EDIT2 : pour l'instant je suis passé sur une solution alternative, j'affiche mon indication dans un évènement qui précède très largement celui qui déclenche ma fonction filemanager.
Marsh Posté le 01-06-2020 à 20:23:31
Code :
|
devrait suffire
https://developer.mozilla.org/fr/do [...] readAsText
Marsh Posté le 01-06-2020 à 21:07:23
J'ai testé (quelques petites erreurs) :
Code :
|
Mais non ça ne le fait pas, le problème vient du fait que le DOM ne se met pas à jour tant que l’exécution du JS n'est pas terminée. Je pensais qu'en passant le JS en asynchrone ça changerait mais non. L'une des astuces trouvée sur stackoverflow est d'utiliser la fonction setTimeout afin de sortir la partie du code qu'elle contient de la pile en cours d'exécution :
https://stackoverflow.com/questions [...] js-running
https://stackoverflow.com/questions [...] ctions-run
Mais ça ne fonctionne pas bien chez moi...
Marsh Posté le 01-06-2020 à 21:22:10
euh, non. LE dom se mettra à jour dès que possible
2eme point : le onload d'un reader est très rapide
est ce que parse et create table sont synchrones ou asynchrones ? Est ce qu'elles sont longues ?
Marsh Posté le 01-06-2020 à 22:33:55
Perso, je serais passé par settimeout() pour le loading.
Marsh Posté le 01-06-2020 à 23:08:18
flo850 a écrit : euh, non. LE dom se mettra à jour dès que possible est ce que parse et create table sont synchrones ou asynchrones ? Est ce qu'elles sont longues ? |
Je ne fais que constater... Le DOM se met à jour certes dès que possible, faut juste définir le quand c'est possible.
Je n'ai pas eu le temps de lire x articles mais ça semble compliqué et peu documenté du peu que j'ai pu lire.
Le problème n'est pas lié au onload mais bien au parsing et surtout au createTable (les deux sont synchrones). D'ailleurs le traitement demande tellement de ressources que même un gif ne s'anime plus, la page est bloquée. Donc j'ai deux pistes, soit tenter d'attacher deux évènements distincts voir si ça peut permettre de dissocier soit tenter d'utiliser un web worker.
Marsh Posté le 02-06-2020 à 08:05:35
Donc settimzoit sur le loading, mais surtout essaye d'optimiser ton traitement ainsi que la génération du dom
Est ce que tu peux déporter le traitement ôté serveur pour n'avoir que la lecture des données ?
Est ce que tu construit les nœuds a la mains où tu utilise des templates ?
Marsh Posté le 02-06-2020 à 08:30:17
C'est vrai qu'un traitement JS qui consomme tellement de ressources que même un gif ne s'anime plus, c'est bizarre Soit le client a un CPU de calculette, soit il faut effectivement revoir la façon dont est effectué le traitement.
Pourquoi ne pas découper le traitement en petits paquets et chaque traitement est fait séquentiellement et entre 2 traitements, tu laisses le CPU respirer qq ms ?
Dans un programme en Delphi, j'avais une grosse boucle de traitement et ça bloquait aussi le CPU à 100%. En ajoutant un processDispatch() à chaque tour de boucle, le CPU pouvait traiter d'autres choses sur le PC.
Marsh Posté le 02-06-2020 à 08:40:37
Faut que je teste aussi ta solution Rufo mais oui l'une des contraintes c'est de se passer de serveur à ce moment là. Avec un serveur tout serait cent fois plus simple...
Je génère à la main sur mon fichier test environ 500 lignes de tableau. Cela prend chez moi un peu moins d'une seconde. J'estime que le temps d'attente est acceptable dans la mesure où l'utilisateur va déjà passer plusieurs secondes à aller chercher son fichier.
Je pourrai en effet ne générer qu'une partie du tableau dans le DOM et faire un chargement sur le scroll mais pas certain que ce soit vraiment mieux que de bloquer la page au grand max 3 secondes pour ensuite être tranquille.
Marsh Posté le 02-06-2020 à 08:56:20
mets au moins une pagination sur le tableau : tu parse les données une seule fois, mais tu n'affiche que 100 éléments avec page suivantes/pages précédentes
Mais 500 lignes de tableau à générer, normalement c'est assez indolore, à moins qu'il n'y a 500 colonnes et/ou que tu fasse un traitement lourd). Je pense que c'est là que tu dois améliorer les choses.
Marsh Posté le 02-06-2020 à 09:23:00
typiquement, avec des templates : https://www.html5rocks.com/en/tutor [...] /template/
si tu as besoin de la compatibilité IE , il faut ajouter un script (attention, IE avec ses perfs de merde va probablement s'etouffer très très vite)
Est ce que tu peux tester un truc simple comme ça ?
Code :
|
Code :
|
Marsh Posté le 02-06-2020 à 10:48:23
flo850 a écrit : mets au moins une pagination sur le tableau : tu parse les données une seule fois, mais tu n'affiche que 100 éléments avec page suivantes/pages précédentes |
Oui c'est ça que je sous-entendais par un chargement sur le scroll.
flo850 a écrit : typiquement, avec des templates : https://www.html5rocks.com/en/tutor [...] /template/ Est ce que tu peux tester un truc simple comme ça ?
|
J'utilise à l'heure actuelle des createElement que je greffe entre eux puis que j'ajoute uniquement à la fin à mon DOM, j'ai l'impression que ça agit comme les fragments HTML car j'avais testé les fragments sans noter d'amélioration. Mais oui je pourrai regarder les templates. Par contre il y a un truc qui me fait peur dans ton code c'est le map, je sais qu'au début j'étais sur un foreach, j'ai voulu passer sur un map à un moment pour simplifier mon code et au final je suis retourné sur un foreach car ça m'avait complètement tué mes performances (10s au lieu d'1s). Je pense que les maps n'aiment pas faire des traitements lourds et le problème c'est que je récupère un csv et je dois traiter les données avant de les afficher, elles ne sont pas prêtes à l'emploi. Je dois garder en mémoire le csv parsé mais non traité en mémoire pour actualiser l'affichage en fonction des entrées client.
EDIT : je teste dès que je peux, c'est à dire dans la semaine...
Marsh Posté le 02-06-2020 à 12:28:30
Je sais pas ce que tu fais dans ton createTable() mais il me semble que faire un .innertHTML = provoque la réévaluation du DOM.
Donc mieux vaut tout faire dans une variable puis faire une seule affectation une fois pour toute dans innerHTML que faire pleins de concaténations.
Marsh Posté le 02-06-2020 à 13:25:19
map/foreach ont exactement la même performance, c'est autre chose qui t'a mangé tes perfs. Tu as combien de colonnes ?
ne garde pas en mémoire le CSV, mais garde en mémoire la version exploitable (un json par exemple)
et oui, une seule modif du dom améliore énormement les perfs
Marsh Posté le 02-06-2020 à 14:39:05
J'utilise appendChild pour ajouter mon noeud à la fin.
Pour le map/foreach, de souvenir je n'avais changé que ça pour retrouver des perfs "correctes", suffit que l'un cause en effet une réévaluation du DOM et pas l'autre pour des raisons que je ne connais pas. C'est bien au-delà de mes connaissances, probablement des choses qu'en temps normal on ne peut remarquer et qui ressortent dans des cas critiques comme le mien.
J'ai 6 colonnes avec parfois plusieurs données dans une cellule et je garde en mémoire un tableau d'objets JS mais avec les données quasi brutes.
Marsh Posté le 02-06-2020 à 16:32:52
Je suis sûr a 100% que ce genre de tableau ne devrait pas faire ramer
Cet après midi, j'ai travaillé sur du parsing de fichier excel côté client, 300 lignes, 8 colonnes, et le navigateur ne fait pas la gueule . A mon avis, tu ne cherche pas au bon endroit en te focalisant sur le DOM.
Marsh Posté le 02-06-2020 à 16:45:17
Pour l'instant je ne cherche rien, je me disais que c'était possible un freeze d'une seconde sur ce genre de traitement (on est d'accord que je génère dynamiquement le tableau ?).
Cela me semblait aussi acceptable compte-tenu du temps de freeze rapporté au temps que l'utilisateur va déjà mettre pour aller chercher son fichier donc je me disais que simplement mettre un avertissement de chargement en cours suffisait.
Maintenant si vous me dites que je peux générer dynamiquement mon tableau en quelques ms (< 250 ms on va dire) je vais en effet chercher de ce côté.
Marsh Posté le 02-06-2020 à 19:08:46
1- Je viens de comprendre que je n'ai pas compris ta solution Rufo sur le setTimeout, j'ai déjà testé de mettre l'affichage du message de chargement en cours dans un setTimeout, ça améliore un peu mais en fonction des propriétés CSS ça peut annuler l'effet...
2- J'ai fait un template, mon code est plus clair mais je ne gagne pas en perfs.
3- En effet j'ai quelques innerHTML qui trainent, en les passante en commentaire ça accélère bien, donc je vais travailler à les remplacer. Pour le reste, on va déjà voir ce que ça donne le travail sur les innerHTML.
Marsh Posté le 02-06-2020 à 19:41:46
Avoir éliminé les innerHTML semble accélérer tout ça, mais ça m'a surtout permis de trouver une fonction qui ralentie tout ça :
Code :
|
Une idée ? (je passe dans le sens "false" )
Parce qu'en écrivant le message j'en vois une :
Spoiler : Il manque un point-virgule à la troisième ligne. En le rajoutant ça accélère, mais pourquoi je n'ai pas eu d'erreur levée ??? |
Je n'ai pas l'air con avec ça.
Par contre j'ai des données avec parfois quelques balises HTML (genre des <br> ), comment ce passer du innerHTML ? Je remplace les balises à la volée ? Car j'ai testé, ça ralentit quand même de laisser juste un innerHTML (ou du moins celui-là).
Marsh Posté le 02-06-2020 à 20:23:33
Ben non, dans innerHTML, tu peux mettre du HTML, ça pose pas de pb. Donc tes <br />, tu peux les laisser sauf si pour le rendu final, t'en veux pas.
Edit : en js, le ; à la fin d'une ligne n'est pas obligatoire.
Marsh Posté le 02-06-2020 à 20:24:40
mais au passage "des" inner html
tu ne veux pas tout mettre dans une grosse chaine de caractère et faire 1 innerhtml au bout ?
Marsh Posté le 02-06-2020 à 20:26:42
C'est clair, ça serait plus rapide.
Marsh Posté le 02-06-2020 à 21:36:31
rufo a écrit : Ben non, dans innerHTML, tu peux mettre du HTML, ça pose pas de pb. Donc tes <br />, tu peux les laisser sauf si pour le rendu final, t'en veux pas. |
Le but c'est de virer le innerHTML, donc oui je sais qu'on peut mettre du HTML dedans c'était bien pour ça que je l'avais utilisé. Maintenant comment faire sans, cela me semble compliqué, soit j'élimine le HTML pour ne laisser que du texte sans même pouvoir faire un retour à la ligne si je comprends bien, soit faut que je parse moi-même pour créer les noeuds et les ajouter (semble compliqué).
Pour le point-virgule, je viens de lire rapidement un truc, je préfère ne pas approfondir puisque a priori son omission fait débat sur les perfs.
Le coup de la chaîne, je n'aime pas trop. Par contre j'ai trouvé des boucles à factoriser.
Marsh Posté le 02-06-2020 à 22:11:48
C'est ma fonction parseDate qui semble critique à l'heure actuelle, elle me bouffe 400 ms, elle est appelée deux fois pour chaque ligne de données. Une idée ?
Marsh Posté le 02-06-2020 à 22:39:00
T'as quoi comme données en entrée et tu veux les transformer en quoi au final ?
Parce qu'il y a peut-être moyen de prendre "des raccourcis" ?
Marsh Posté le 02-06-2020 à 23:15:59
MaybeEijOrNot a écrit : |
tu fais de la micro optimisation alors que là, c'est majeur
pour le parsing de date, c'est forcement un peu long
8,050 ops/s ±1.87%
Code :
|
216,629 ops/s ±2.49%
Code :
|
243,894 ops/s ±1.08%
Code :
|
Marsh Posté le 02-06-2020 à 23:19:26
Je pense même qu'en se passant des objets, ça irait encore plus vite.
Marsh Posté le 02-06-2020 à 23:27:33
pas sur qu'on gagne tant que ca, et faut gérer a la main la conversion
Marsh Posté le 03-06-2020 à 10:12:42
flo850 a écrit :
|
Je savais bien que tenter de bien faire les choses était une mauvaise idée, j'aurai vraiment dû y aller à la bourrin et parser moi-même comme je l'ai fait partout ailleurs.
Je testerai quand même de tout mettre dans une string et d'ajouter à la fin mais je ne suis pas persuadé de l'efficacité. Disons que ça va m'éliminer des réinterprétations du DOM si je ne les ai pas toutes enlevées, sinon ça devrait faire la même chose. Mais c'est quand même moins beau et surtout plus galère à gérer.
Faut savoir qu'après avoir créé mon tableau, je repasse en revue chaque cellule de la dernière colonne afin de récupérer ses dimensions pour gérer son overflow car je veux limiter mes hauteurs de lignes (sans "perdre" de données donc j'ajoute la possibilité d'agrandir la hauteur de la ligne au besoin). Mais ça n'a pas l'air de vraiment consommer de ressources.
Sinon j'ai tout rebasculé dans une même boucle quelque chose comment 6 boucles, et en effet ça ne gagne pas grand chose car si je comprends ça crée des problèmes de gestion de la mémoire qui sont aussi longs que de recommencer les boucles.
Marsh Posté le 03-06-2020 à 18:54:45
flo850 a écrit :
|
Très efficace, merci ! (euh enfin ça va vite mais le formatage ce n'est pas encore ça, je vais ajuster)
Quand j'aurai un peu plus de temps, je vais essayer la technique de la string et je vais tenter d'utiliser ton site de benching pour repérer d'autres aberrations car pour l'instant j'utilise l'outil de performances de FF et ce n'est pas évident d'avoir les réponses directes sans faire de différentiel.
EDIT : version corrigée du code :
Code :
|
Marsh Posté le 04-06-2020 à 14:20:57
MaybeEijOrNot a écrit :
|
Ca que j'adore avec ES6 c'est la décomposition et les literals
Code :
|
Marsh Posté le 01-06-2020 à 15:07:57
Bonjour,
J'ai une fonction qui traite un fichier texte, cela peut parfois durer quelques secondes, je voudrais donc afficher une indication de chargement en cours mais je me suis complètement perdu dans les async, await, promises et .then.
Je n'ai vraiment plus les idées claires...
Voici ma fonction :
Je voudrai donc afficher mon élément "loading" le temps que le traitement de la fonction parse() et createTable() soit réalisé. Ces deux fonctions doivent être réalisées de manière séquentielle (l'une après l'autre) mais dans un contexte asynchrone afin de permettre l'affichage du loader.
Un coup de pouce ?
Message édité par MaybeEijOrNot le 01-06-2020 à 15:08:54
---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.