Fermer

octobre 1, 2023

Retarder, mettre en veille, mettre en pause et attendre en JavaScript —

Retarder, mettre en veille, mettre en pause et attendre en JavaScript —

De nombreux langages de programmation ont un sleep fonction qui retardera l’exécution d’un programme pendant un nombre de secondes donné. JavaScript ne dispose pas de cette fonctionnalité intégrée, mais ne vous inquiétez pas. Dans cet article, nous explorerons diverses techniques pour implémenter des retards dans votre code JavaScript, en gardant à l’esprit la nature asynchrone du langage.

Table des matières

Comment créer une fonction de veille en JavaScript

Pour ceux d’entre vous qui sont ici pour une solution rapide et qui ne veulent pas entrer dans les détails techniques, nous avons ce qu’il vous faut. Voici le moyen le plus simple d’ajouter une fonction de veille à votre boîte à outils JavaScript :

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });

Exécutez ce code et vous verrez « Bonjour » apparaître dans votre console. Puis, après une brève pause de deux secondes, « World ! suivra. C’est un moyen simple et efficace d’introduire un délai sans transpirer.

Si c’est tout ce que vous êtes venu chercher, fantastique ! Mais si vous êtes curieux de connaître le « pourquoi » et le « comment », il y a encore beaucoup à apprendre. Il existe des nuances et des subtilités dans la gestion du temps en JavaScript qui pourraient vous être utiles. Alors continuez à lire pour en savoir plus !

Comprendre le modèle d’exécution de JavaScript

Maintenant que nous avons une solution rapide à notre actif, examinons les mécanismes du modèle d’exécution de JavaScript. Comprendre cela est crucial pour gérer efficacement le temps et les opérations asynchrones dans votre code.

Considérez le code Ruby suivant :

require 'net/http'
require 'json'

url = 'https://api.github.com/users/jameshibbard'
uri = URI(url)
response = JSON.parse(Net::HTTP.get(uri))
puts response['public_repos']
puts 'Hello!'

Comme on pouvait s’y attendre, ce code demande à l’API GitHub de récupérer mes données utilisateur. Il analyse ensuite la réponse, affiche le nombre de dépôts publics attribués à mon compte GitHub et affiche enfin « Bonjour ! » à l’écran. L’exécution va de haut en bas.

Comparez cela avec la version JavaScript équivalente :

fetch('https://api.github.com/users/jameshibbard')
  .then(res => res.json())
  .then(json => console.log(json.public_repos));
console.log('Hello!');

Si vous exécutez ce code, il affichera « Bonjour ! » à l’écran, alors le nombre de dépôts publics attribués à mon compte GitHub.

En effet, la récupération de données à partir d’une API est une opération asynchrone en JavaScript. L’interpréteur JavaScript rencontrera le fetch commander et expédier la demande. Ce sera pas, cependant, attendez que la demande soit terminée. Au contraire, il continuera son chemin et affichera « Bonjour ! » à la console, puis lorsque la requête reviendra quelques centaines de millisecondes plus tard, elle affichera le nombre de dépôts.

Si tout cela est nouveau pour vous, vous devriez regarder cette excellente conférence : De toute façon, qu’est-ce que c’est que la boucle d’événements ?

Comment utiliser correctement SetTimeout en JavaScript

Maintenant que nous comprenons mieux le modèle d’exécution de JavaScript, voyons comment JavaScript gère les retards et le code asynchrone.

La manière standard de créer un délai en JavaScript consiste à utiliser son setTimeout méthode. Par exemple:

console.log('Hello');
setTimeout(() => {  console.log('World!'); }, 2000);

Cela enregistrerait « Bonjour » sur la console, puis après deux secondes « Monde ! » Et dans de nombreux cas, cela suffit : faites quelque chose, puis, après un court délai, faites autre chose. Trié !

Mais malheureusement, les choses ne sont pas toujours aussi simples.

Vous pourriez penser que setTimeout met tout le programme en pause, mais ce n’est pas le cas. C’est une fonction asynchrone, ce qui signifie que le reste de votre code n’attendra pas qu’il soit terminé.

Par exemple, disons que vous exécutez ceci :

console.log('Hello');
setTimeout(() => { console.log('World!'); }, 2000);
console.log('Goodbye!');

Vous verrez le résultat suivant :

Hello
Goodbye!
World!

Remarquez comment « Au revoir ! » apparaît avant « Monde ! » ? C’est parce que setTimeout ne bloque pas l’exécution du reste du code.

Cela signifie que vous ne pouvez pas faire ceci :

console.log('Hello');
setTimeout(1000);
console.log('World');

« Bonjour » et « Monde » seront immédiatement enregistrés sur la console sans aucun délai notable entre les deux.

Vous ne pouvez pas non plus faire ceci :

for (let i = 0; i < 5; i++) {
  setTimeout(() => { console.log(i); }, i * 1000);
}

Prenez une seconde pour réfléchir à ce qui pourrait se produire dans l’extrait de code ci-dessus.

Il ne le fera pas imprimez les chiffres de 0 à 4 avec un délai d’une seconde entre chacun. Au lieu de cela, vous obtiendrez en réalité cinq 4 imprimés en même temps après quatre secondes. Pourquoi? Parce que la boucle ne suspend pas l’exécution. Il n’attend pas setTimeout à terminer avant de passer à l’itération suivante.

Donc qu’est-ce setTimeout vraiment bon pour ? Regardons cela maintenant.

Examen de la fonction setTimeout() et meilleures pratiques

Comme vous pouvez le lire notre setTimeout Didacticielle JavaScript natif setTimeout la fonction appelle une fonction ou exécute un extrait de code après un délai spécifié (en millisecondes).

Cela peut être utile si, par exemple, vous souhaitez afficher une fenêtre contextuelle après qu’un visiteur ait parcouru votre page pendant un certain temps, ou si vous souhaitez un court délai avant de supprimer un effet de survol d’un élément (au cas où l’utilisateur accidentellement souris).

Le setTimeout La méthode accepte une référence à une fonction comme premier argument.

Cela peut être le nom d’une fonction :

function greet(){
  alert('Howdy!');
}
setTimeout(greet, 2000);

Il peut s’agir d’une variable qui fait référence à une fonction (une expression de fonction) :

const greet = function(){
  alert('Howdy!');
};
setTimeout(greet, 2000);

Ou bien il peut s’agir d’une fonction anonyme (dans ce cas, une fonction flèche) :

setTimeout(() => { alert('Howdy!'); }, 2000);

Il est également possible de passer setTimeout une chaîne de code à exécuter :

setTimeout('alert('Howdy!');', 2000);

Cependant, cette méthode n’est pas recommandée car :

  • c’est difficile à lire (et donc difficile à maintenir et/ou déboguer)
  • il utilise un implicite evalce qui constitue un risque potentiel pour la sécurité
  • c’est plus lent que les alternatives, car il doit invoquer l’interpréteur JS

Comme mentionné, setTimeout est idéal pour déclencher une action ponctuelle après un délai, mais il est également possible d’utiliser setTimeout (ou son cousin setInterval) pour faire attendre JavaScript jusqu’à ce qu’une condition soit remplie. Par exemple, voici comment vous pourriez utiliser setTimeout attendre qu’un certain élément apparaisse sur une page Web :

function pollDOM () {
  const el = document.querySelector('my-element');

  if (el.length) {
    
  } else {
    setTimeout(pollDOM, 300); 
  }
}

pollDOM();

Cela suppose que l’élément apparaîtra à un moment donné. Si vous n’êtes pas sûr que ce soit le cas, vous devrez envisager d’annuler la minuterie (en utilisant clearTimeout ou clearInterval).

Augmentation des délais d’attente comme alternative à la fonction veille en JavaScript

Parfois, vous pourriez avoir envie d’introduire des retards dans une séquence d’opérations. Bien que vous puissiez utiliser diverses méthodes pour émuler une fonction de veille, il existe une autre approche qui est souvent négligée : l’augmentation progressive des délais d’attente.

L’idée est simple : au lieu de mettre en pause tout le thread d’exécution, vous incrémentez le délai pour chaque opération suivante en utilisant setTimeout. Cela vous permet de créer une séquence d’actions différées sans bloquer le navigateur ni compromettre l’expérience utilisateur.

Voici un exemple rapide pour illustrer :

let delay = 1000; 

for (let i = 0; i < 5; i++) {
  setTimeout(() => {
    console.log(`This is message ${i + 1}`);
  }, delay);

  delay += 1000; 
}

Dans cet exemple, le premier message apparaîtra après 1 seconde, le deuxième après 2 secondes, et ainsi de suite, jusqu’au cinquième message après 5 secondes.

Les avantages de cette méthode sont qu’elle est non bloquante, facile à mettre en œuvre et ne nécessite pas de connaissance des promesses ou des promesses. async/await. Cependant, il ne convient pas aux opérations asynchrones complexes qui nécessitent un timing précis ou une gestion des erreurs.

Contrôle de flux en JavaScript moderne

Il arrive souvent, lors de l’écriture de JavaScript, que nous devions attendre que quelque chose se produise (par exemple, que des données soient récupérées à partir d’une API), puis faire quelque chose en réponse (comme mettre à jour l’interface utilisateur pour afficher les données).

L’exemple ci-dessus utilise une fonction de rappel anonyme à cet effet, mais si vous devez attendre que plusieurs choses se produisent, la syntaxe devient rapidement assez compliquée et vous vous retrouvez dans rappel en enfer.

Heureusement, le langage a considérablement évolué ces dernières années et nous propose désormais de nouvelles constructions pour éviter cela.

Par exemple, en utilisant attente asynchrone nous pouvons réécrire le code initial pour récupérer les informations de l’API GitHub :

(async () => {
  const res = await fetch(`https://api.github.com/users/jameshibbard`);
  const json = await res.json();
  console.log(json.public_repos);
  console.log('Hello!');
})();

Désormais, le code s’exécute de haut en bas. L’interpréteur JavaScript attend que la requête réseau soit terminée et que le nombre de dépôts publics soit enregistré en premier, puis le message « Bonjour ! » message.

Si c’est plutôt le genre de chose que vous essayez d’accomplir, je vous encourage à lire notre article Contrôle de flux dans JS moderne : rappels des promesses d’asynchrone/d’attente.

Mettre en veille le JavaScript natif

Si vous êtes toujours avec moi, alors je suppose que vous êtes plutôt déterminé à bloquer ce thread d’exécution et à faire attendre JavaScript.

Voici comment procéder :

function sleep(milliseconds) {
  const date = Date.now();
  let currentDate = null;
  do {
    currentDate = Date.now();
  } while (currentDate - date < milliseconds);
}

console.log('Hello');
sleep(2000);
console.log('World!');

Comme prévu, cela enregistrera « Bonjour », fera une pause de deux secondes, puis enregistrera « Monde ! »

Cela fonctionne en utilisant le Date.maintenant méthode pour obtenir le nombre de millisecondes écoulées depuis le 1er janvier 1970 et attribuer cette valeur à un date variable. Il crée alors un vide currentDate variable, avant de saisir une do ... while boucle. Dans la boucle, il récupère à plusieurs reprises le nombre de millisecondes écoulées depuis le 1er janvier 1970 et attribue la valeur à la valeur déclarée précédemment. currentDate variable. La boucle continuera jusqu’à ce que la différence entre date et currentDate est inférieur au délai souhaité en millisecondes.

Travail terminé, n’est-ce pas ? Enfin, pas tout à fait…

Comment écrire une meilleure fonction de sommeil en JavaScript

Peut-être que ce code fait exactement ce que vous espérez, mais sachez qu’il présente un gros inconvénient : la boucle bloquera le thread d’exécution de JavaScript et garantira que personne ne pourra interagir avec votre programme jusqu’à ce qu’il soit terminé. Si vous avez besoin d’un délai important, il est possible que cela fasse même planter complètement les choses.

Alors que faire?

Eh bien, il est également possible de combiner les techniques apprises plus tôt dans l’article pour créer une méthode de sommeil moins intrusive :

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });

Ce code enregistrera « Bonjour », attendra deux secondes, puis enregistrera « Monde ! » Sous le capot, nous utilisons le setTimeout méthode pour résoudre un promesse après un nombre donné de millisecondes.

Notez que nous devons utiliser un then rappel pour vous assurer que le deuxième message est enregistré avec un délai. Nous pouvons également enchaîner plus de fonctions de rappel sur la première :

console.log('Hello');
sleep(2000)
  .then(() => { console.log('World!'); })
  .then(() => {
    sleep(2000)
      .then(() => { console.log('Goodbye!'); })
    });

Cela fonctionne, mais ça a l’air moche. Nous pouvons le embellir en utilisant async ... await:

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function delayedGreeting() {
  console.log('Hello');
  await sleep(2000);
  console.log('World!');
  await sleep(2000);
  console.log('Goodbye!');
}

delayedGreeting();

Cela semble plus joli, mais cela signifie que quel que soit le code utilisant le sleep la fonction doit être marquée comme async.

Bien entendu, ces deux méthodes présentent toujours l’inconvénient (ou la particularité) d’être ne le faites pas mettre en pause toute l’exécution du programme. Seule votre fonction dort :

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function delayedGreeting() {
  console.log('Hello');
  await sleep(2000); 
  console.log('World!');
}

delayedGreeting();
console.log('Goodbye!');

Le code ci-dessus enregistre les éléments suivants :

Hello
Goodbye!
World!

Meilleures pratiques pour créer une fonction de veille JavaScript

Nous avons exploré différentes manières d’introduire des retards dans JavaScript. Récapitulons maintenant quelle méthode est la mieux adaptée aux différents scénarios et laquelle vous devriez généralement éviter.

1. Plaine setTimeout

console.log('Hello');
setTimeout(() => { console.log('World!'); }, 2000);
  • 👍 Avantages: Simple à comprendre, non bloquant.
  • 👎 Les inconvénients: Offre un contrôle limité sur les opérations asynchrones.
  • 📝 Quand utiliser: Idéal pour les retards simples et ponctuels ou les interrogations de base.

2. Incrémentiel setTimeout

setTimeout(() => { console.log('Hello'); }, 1000);
setTimeout(() => { console.log('World!'); }, 2000);
  • 👍 Avantages: Non bloquant, facile à mettre en œuvre et ne nécessite pas de connaissance des promesses ou d’async/wait.
  • 👎 Les inconvénients: Ne convient pas aux opérations asynchrones complexes. Aucune gestion des erreurs.
  • 📝 Quand utiliser: Utile pour les séquences simples avec un délai entre chaque étape.

3. Bloquer la boucle d’événements avec une boucle

console.log('Hello');
const date = Date.now();
let currentDate = null;
do {
  currentDate = Date.now();
} while (currentDate - date < 2000);
console.log('World!');
  • 👍 Avantages: Imite le comportement de sommeil traditionnel.
  • 👎 Les inconvénients: bloque l’intégralité du thread, peut geler l’interface utilisateur ou planter le programme.
  • ⚠️ Fortement déconseillé: N’utilisez cette méthode que si vous devez absolument interrompre l’exécution et que vous êtes conscient des risques.

4. Utiliser des promesses avec setTimeout

const sleep = function(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
console.log('Hello');
sleep(2000).then(() => { console.log('World!'); });
  • 👍 Avantages: Non bloquant, plus de contrôle sur les opérations asynchrones.
  • 👎 Les inconvénients: Nécessite une compréhension des promesses. Les chaînes de promesses plus longues peuvent devenir un peu compliquées.
  • 📝 Quand utiliser: Lorsque vous avez besoin de plus de contrôle sur le timing et les opérations asynchrones.

5. Utilisation async/await avec des promesses

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function delayedGreeting() {
  console.log('Hello');
  await sleep(2000);
  console.log('World!');
  await sleep(2000);
  console.log('Goodbye!');
}

delayedGreeting();
  • 👍 Avantages: Syntaxe propre, facile à lire, non bloquante.
  • 👎 Les inconvénients: Nécessite une compréhension de async/await et des promesses. Nécessite une fonction « wrapping » en dehors des modules.
  • Fortement recommandé: Il s’agit de l’approche la plus moderne et la plus propre, en particulier lorsqu’il s’agit de plusieurs opérations asynchrones.

Conclusion

Les problèmes de timing en JavaScript sont à l’origine de nombreux maux de tête pour les développeurs, et la façon dont vous les gérez dépend de ce que vous essayez d’accomplir.

Bien qu’une fonction de mise en veille soit présente dans de nombreux autres langages, je vous encourage à adopter la nature asynchrone de JavaScript et à essayer de ne pas combattre le langage. C’est en fait plutôt sympa quand on s’y habitue.

Si vous avez des questions, rendez-vous sur le Forums SitePoint et lancez une discussion.

FAQ sur les fonctions de veille, de pause et d’attente en JavaScript

Voici quelques questions fréquemment posées sur la création de retards dans JavaScript.

Y a-t-il un sommeil en JavaScript ?

Non, JavaScript n’a pas de fonction de veille intégrée, mais vous pouvez en émuler une en utilisant setTimeout ou des promesses avec async/await.

Est-il possible d’utiliser la fonction JavaScript sleep dans des boucles ?

Oui, vous pouvez utiliser la fonction sleep en boucle si vous travaillez dans un async fonction ou un module :
async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms));
}
for (let i = 0; i < 5; i++) { console.log(`Loop count: ${i}`); await sleep(1000); // Sleep for 1 second
}

Comment dormir 1 seconde en JavaScript ?

Vous pouvez utiliser setTimeout comme ça:
setTimeout(() => { console.log('1 second passed'); }, 1000);
Ou utiliser async/await avec des promesses :
await new Promise(resolve => setTimeout(resolve, 1000)) .then(() => { console.log('1 second passed'); });

Comment dormir 5 secondes en JavaScript ?

Semblable à dormir pendant 1 seconde, changez simplement la durée à 5 000 millisecondes :
setTimeout(() => { console.log('5 seconds passed'); }, 5000);
Ou utiliser async/await avec des promesses :
await new Promise(resolve => setTimeout(resolve, 5000))
.then(() => { console.log('5 seconds passed'); });

Comment faire un timeout en JavaScript ?

Vous pouvez créer un délai d’attente à l’aide du setTimeout fonction:
setTimeout(() => { /* Your code here */ }, timeInMilliseconds);

Qu’est-ce que wait() faire en JavaScript ?

Il n’y a pas de natif wait() fonction en JavaScript. Cependant, vous pouvez créer un effet similaire en utilisant async/await avec des promesses ou setTimeout.




Source link