En PHP, il est possible de provoquer un délai d'attente dans l'exécution d'un script, c'est l'instruction sleep. Vous serez ravis d'apprendre qu'elle n'existe pas en JavaScript.
Si vous êtes là, c'est que vous cherchez une solution simple pour 'attendre' dans un script.
Je vais vous donner cette solution et ensuite, je vous dirai aussi pourquoi ce n'est pas une bonne pratique de l'utiliser.
sleep en JavaScript : setTimeout
Dans un utilitaire, ajoutez ceci :
export const sleep(ms) = {
return new Promise((res) => {
setTimeout(() => res(), ms)
})
}
Puis, un await lors de l'appel et voilà, vous avez votre sleep.
Maintenant, on va voir ensemble comment faire autrement et pourquoi.
Sleep en JavaScript, une mauvaise idée ?
Côté serveur (Node.js)
Connaissez-vous le fonctionnement de l'event loop en Node.js ?
Une API appelée libuv permet à Node.js de traiter les entrées et les sorties de façon asynchrone et non-bloquante, elle est aussi mono-thread. C'est-à-dire qu'une seule instance du programme est exécutée.
Concrètement, cela signifie que les instructions sont exécutées dans l'ordre d'apparition dans le code.
Par exemple, un code asynchrone va s'exécuter dès qu'il est lu, libre à vous de demander au thread d'attendre le retour ou non (avec ou sans .then / await)
C'est ici que l'utilisation d'un sleep pose problème. Vous forcez le thread principal et unique à attendre durant le temps que vous lui aurez affecté.
Dans un monde de la performance, bloquer inutilement l'exécution de Node, qui a été conçu pour être performant, est un paradoxe.
Personnellement, je ne l'utilise pas.
Si vous sentez ne pas avoir le choix dans l'utilisation d'un sleep, c'est que votre code a un problème de conception.
Par exemple, si vous l'utilisez pour attendre la fin d'une exécution à un autre endroit du code, vous devez réfléchir à modifier votre implémentation. Vous pouvez par exemple utiliser une machine à état, ou tout simplement une instruction Promise.allSettled.
Côté client (React)
Dans le cas d'un script exécuté sur le navigateur, ce type d'instruction peut bloquer complètement les interactions de votre site.
Vous n'avez sûrement pas envie que vos utilisateurs soient incapables d'utiliser votre site.
Sur ce blog, j'ai été confronté à ce problème.
Pour colorer les exemples de code, j'utilise une librairie nommée highlight.js.
Comme j'ai transféré les articles de ce blog depuis un autre, non développé en React, j'ai implémenté highlight.js lors du rendu du composant des articles :
function HtmlArticle({ slug }) {
useEffect(() => {
setTimeout(() => {
hljs.highlightAll()
}, 1000)
}, [])
return lazy(() => import(`../../articles-tsx/${slug}.tsx`).catch(() => import('../404/404.tsx')))
}
Cette solution, bien que simple, est inefficace.
L'utilisateur se rend sur la page, commence à la lire et là, le contenu change (parfois pas), au bout d'une seconde.
Face à cette mauvaise implémentation, j'ai déplacé la logique dans chaque composant article qui utilise la balise code :
useEffect(() => {
hljs.highlightAll()
}, [])
useEffect avec [] est l'équivalent de componentDidMount, c'est-à-dire qu'il est appelé après le premier rendu, donc parfait pour la coloration syntaxique.
sleep en JavaScript, les cas où il est possible de l'utiliser
Il ne faut pas utiliser de sleep dans un code JavaScript, sauf cas exceptionnel.
Un de ces cas est particulièrement utilisé par les sites qui souhaitent à tout prix retenir les utilisateurs (ce n'est pas le cas du mien).
Imaginez que vous faites une promo de dingue sur votre e-commerce. Votre client potentiel se rend sur la page produit et au bout de 10 secondes, une modale s'ouvre, lui expliquant que si il commande maintenant, il bénéficiéra de 20% de remise.
Vous devez implémenter un sleep, vous n'avez pas trop le choix.
D'un point de vue UX, je ne suis pas friand de ce type de pratique, mais elle sont très répandues.