Les bons développeurs javascript utilisent les événements, à toutes les sauces. En fait quasiment tout ce qui est fait en javascript est en réaction à un événement. On arrive à deux problématiques qui ont un un impact plus ou moins important sur les performances :
Diminuer la sensibilité
Notre premier problème se voit assez facilement sur les aides à la saisie, par exemple celles qu’on trouve sur les moteurs de recherche. Vous avez forcément rencontré la chose : vous saisissez quelques lettres dans un champ texte, et le navigateur vous propose de compléter votre saisie, avec une liste des choix les plus fréquents.
Jusque là aucun problème. Sauf que si ce petit code tourne trop souvent ce sont plusieurs aller-retours fréquents qui vont être faits au serveur. Cela handicape votre navigateur – qui a une limite de connexions parallèles -, le serveur – qui répond donc moins rapidement -, et votre machine – qui exécute plus de javascript que nécessaire.
Pour jouer les stéréotypes je vais faire une recherche sur Angelina Jolie. Je sais ce que je tape, éventuellement je ne sais pas quelle est la bonne orthographe du nom de famille.
Tout d’abord il est inutile de lancer une aide à la saisie tant que je n’ai pas fini de saisir du texte. Je vais taper Angelina en entier, sans problèmes, sans délais. Lancer une aide dès que j’ai tapé « Ange » sera inutile. Les résultats ne seront pas pertinents et arriveront trop tard, quand j’aurai déjà taper tout ce qu’il faut. Pire, pour peu qu’ils me fassent une proposition sur « Anges et démons » je peux me retrouver perdu.
La première règle est donc de differer le traitement, de ne le lancer qu’après quelques dizaines de millisecondes, si et seulement si il n’y a aucune nouvelle frappe – et bien sûr d’annuler la requête si un nouvel événement apparaît avant la réponse (ici c’est une nouvelle frappe clavier). C’est ce que propose Nicholas C. Zakas sur le YUIBlog.
Pour peaufiner la durée d’attente peut varier suivant le nombre de caractères. A moins de quatre ou cinq caractères on peut mettre un temps d’attente important, parce qu’il est vraissembable que l’utilisateur complètera sa saisie pour continuer, et que les suggestions ont peu de chances d’être pertinentes.
Rassembler les événements
Le traitement des événements peut être gênant, mais sa collecte aussi. Attacher des centaines de gestionnaires d’événement a un coût, surtout sur les anciennes machines. Là dessus un ajoute que sur les vieux navigateurs il est assez facile de générer des fuites de mémoire et cela se multiplie par le nombre de gestionnaires d’événement.
La solution se nomme couramment event délégation (délégation d’événement). Imaginons un menu avec différents liens, vous voulez surveiller le clic ou le survol de chaque élément de la liste. Au lieu de lancer un gestionnaire d’événement par item, la délégation d’événement vous propose d’attacher votre gestionnaireur la liste elle même, puis de vérifier sur quel item a eu lieu l’événement afin de savoir quelle action lancer.
Julien Lecomte en parle dans sa présentation High Performance Ajax Applications aux dernières conférences Velocity mais d’autres donnent plus de détails : par exemple Christian Heilmann avec un long article assez complet sur le YUIBlog sur comment et pourquoi faire de la délégation d’événement, avec un exemple sur son site personnel. Si vous n’aimez pas YUI SitePoint fait un article très court pour une gestion à la main, ce qui n’est pas vraiment plus complexe.
on pourrait aussi envisager stocker les résultats précédent pour les cas ou on retire des lettres?
Difficile d’évaluer le moment où l’utilisateur a finit d’écrire un élément, puisque certaines personne tapent très lentement au clavier.
Très bonne idée que d’augmenter le délai avant les 4 ou 5 premières lettres toutefois !
Il est difficile de savoir quand quelqu’un finit réellement de taper, mais s’il est vraiment trop lent, alors les propositions de complétion ont le temps d’apparaitre entre deux frappes de lettre et seront même d’autant plus appréciées.
Un bête timer me parait suffiant, mais si vous avez d’autres idées pour éviter les requêtes inutiles, je les ajouterai avec plaisir dans le billet
François, oui, pour tous ces trucs dynamiques qui font des requêtes XmlHttpRequest ou autre, il est évident que si on a pas besoin de données rafraîchies à la seconde près, faire son propre cache local est indispensable. C’est d’ailleurs relativement trivial dans le cas d’un autocomplete.
Par contre, faut quand même penser à ce qu’il ne grossisse pas inutilement, et le limiter à nombre d’entrées ou un truc du genre pour éviter de pomper trop de mémoire.
Très intéressant, merci pour l’info !