Also available in: English
Si vous pratiquez couramment le JS, vous avez certainement remarqué que certains évènements sont déclenchés de manière assez ponctuelle, et d’autres peuvent être déclenchés de manière très fréquente et devenir assez difficile à gérer, c’est le cas de « onscroll » et « onresize » par exemple.
Lorsque vous implémentez un écouteur d’évènement sur l’un de ces évènements (je vais prendre « onresize » pour les exemples suivants), vous verrez rapidement, au redimensionnement de la fenêtre, que ceux-ci sont exécutés à chaque changement de pixel dans la largeur de la fenêtre.
Le code utilisé la plupart du temps
Souvent, et de manière assez simple, nous implémentons un écouteur de la sorte :
window.addEventListener('resize', function(){
console.log('resizing');
});
Si vous ajoutez ça dans les scripts JS de votre projet, et que vous ouvrez la page sur votre navigateur, vous constaterez en ouvrant votre console (F12) et en redimensionnant la fenêtre, que la console s’affole un peu.
Imaginez qu’à la place d’un console.log()
votre script fasse un contrôle dans le DOM, change la structure sous certaines conditions (largeur d’écran, visibilité d’un élément, par exemple), etc. etc., et ce à chaque pixel du redimensionnement…
Ne vous moquez pas, on est d’accord que le redimensionnement de la fenêtre ainsi fait n’est pas fréquent chez l’utilisateur, mais c’était la méthode d’un client pour tester si le responsive marchait bien, et il trouvait que ça ramait un peu sur son Mac. Je ne lui en veux pas, il a probablement lu quelque part que le responsive c’est quand on redimensionne la fenêtre de son navigateur.
Bref, on peut optimiser la fréquence d’exécution de tout ce code au redimensionnement, voyons cela.
« C’est le même, mais en différent »
Le principe est de créer un timeout
qu’on lance au redimensionnement et qu’on détruit au redimensionnement. Oui je sais, c’est bizarre comme logique, mais vous allez comprendre.
var the_timer;
window.addEventListener('resize', function(){
clearTimeout(the_timer);
the_timer = setTimeout(function(){
console.log('resized');
}, 75);
});
Pour vous donner une courte explication, il suffit de lire le code de manière linéaire : au moment du redimensionnement, nous supprimons le timeout
(cela arrête l’exécution de la fonction en paramètre), puis nous lançons le timeout
. Celui-ci possède un délai d’exécution de 75 millisecondes. Donc, si entre le premier déclenchement de « resize » et le second, moins de 75 ms se sont écoulées, le timeout
est réinitialisé avant même l’exécution de la fonction en premier paramètre. Vous m’avez suivi ?
Ce qui fait que cela fonctionne, c’est la variable (globale) the_timer
déclarée avant l’écouteur.
Et voilà, c’est un peu mieux quand même. La fréquence, ou « sensibilité » se règle au nombre de millisecondes (ici 75
) renseigné pour le timeout
. Au plus vous augmentez ce chiffre, au moins le contenu de votre fonction sera exécuté rapidement.
Cette méthode n’est pas forcément adaptée à tous les cas pour tous les projets, notamment dans le cadre de l’évènement « onscroll », mesurez donc bien l’impact de cette implémentation 🙂
J’espère que cette astuce vous sera utile.
Super astuce, je l’ai mise en place directement sur un site en cours de développement (même si en effet, le resize est là principalement à des fins de tests plutôt qu’une vraie fonctionnalité)
Pourquoi pas requestAnimationFrame ?
Cela rendra les appels à l’eventListener plus rapide tout en garantissant de belle perf.
Bonjour également,
Par méconnaissance j’imagine 😉
Mais à la lecture de la doc, probablement également à cause du mauvais support, maintenant.
Supporté à partir de IE10, c’est pas super cool quand on voit les stats actuelles.
Tu as un exemple pratique de son utilisation ? Je ne suis pas sûr que cela rentre dans la plupart de mes usages de l’astuce présentée ici.
Merci et bonne soirée !
Bon j’ai été grillé! marcelfalliere a été plus rapide, du coup je complète la réponse: voilà un polyfill requestAnimationFrame() fonctionnant bien pour IE<10 https://gist.github.com/paulirish/1579671 et voilà une illustration pratique bien expliquée: Demo http://davegamache.com/parallax/ et article https://medium.com/@dhg/parallax-done-right-82ced812e61c
Ah ah 🙂
Du coup tu grilles marcelfalliere dans son éventuelle réponse !
Merci à toi, je vais potasser cela et probablement mettre à jour l’article en conséquence !
Bonne soirée.
J’ai vu tout ces mails hier soir mais j’étais dans un endroit très peu servi par l’internet mondial et multimédia.
Content d’avoir aidé 🙂
Pourquoi ne pas utiliser requestAnimationFrame() pour être calé sur la fréquence de rafraichissement du navigateur ?
Pas con ! 🙂
Hello,
Du coup pour répondre aux questions concernant requestAnimationFrame(), dans les cas d’utilisation que j’ai de mon astuce (exécution d’autres portions de code JS), je n’ai pas besoin que celui-ci s’exécute aussi souvent pour des raisons de performance.
La mise en place d’un timer permet de soulager la navigateur et rend la navigation beaucoup plus fluide.
Par contre dans le cadre d’animations fluides et d’exécution de JS modérée, cette fonction remplit plutôt bien son rôle.
Deux outils pour deux objectifs différents 🙂
Merci à vous !
Je dit bravo et Merci.
Après 2 jours de galères a chercher pourquoi ma console affichait 5 a 20 fois les mêmes messages, et cherché quelle fonction
ralentissait l’affichage a chaque resize de la fenêtre ( je suis sur mon site en responcive, la boucle était la a chaque rotation du smartphone) .
Grace a cette solution j’ai optimisé mon site et je ne me perd plus dans la console de débugage, alors encore Merci et bravo.
Ced
Merci pour ton retour d’expérience 🙂