Fermer

novembre 28, 2019

Retard, sommeil, pause et attente en JavaScript –


De nombreux langages de programmation ont une fonction en veille qui retardera l’exécution d’un programme d’un nombre donné de secondes. Cette fonctionnalité est cependant absente de JavaScript en raison de sa nature asynchrone. Dans cet article, nous verrons brièvement pourquoi cela pourrait être, puis comment nous pourrions implémenter nous-mêmes une fonction de sommeil .

Nous avons réécrit ce guide populaire à partir de zéro pour fournir le meilleur et le plus haut. conseils à jour. Cet article a été mis à jour en novembre 2019.

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

Avant de commencer, il est important de bien comprendre le modèle d'exécution de JavaScript.

Considérez le code Ruby suivant:

 require 'net / http '
nécessite 'json'

url = 'https://api.github.com/users/jameshibbard'
URI = URI (URL)
response = JSON.parse (Net :: HTTP.get (uri))
met la réponse ['public_repos']
met "Bonjour!"

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 pensions publiques attribuées à mon compte GitHub et affiche finalement «Hello!» À l'écran. L'exécution va de haut en bas.

Comparez cette version à la version JavaScript équivalente:

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

Si vous exécutez ce code, il affichera «Hello!» À l'écran, puis le nombre de pensions publiques attribuées à mon compte GitHub.

En effet, l'extraction de données à partir d'une API est une opération asynchrone en JavaScript. L'interprète JavaScript rencontrera la commande fetch et enverra la demande. Il ne n'attendra toutefois pas que la demande soit complète. Au lieu de cela, il continuera son chemin, en envoyant «Hello!» À la console, puis, lorsque la demande reviendra quelques centaines de millisecondes plus tard, le nombre de mises en pension sera généré.

Si cela vous intéresse, vous devriez regarder cette excellente conférence: De toute façon, quelle est la boucle de l'événement? .

Vous n'avez peut-être pas besoin d'une fonction de sommeil

Maintenant que nous avons une meilleure compréhension du modèle d'exécution de JavaScript, Voyons comment JavaScript gère les retards et les opérations asynchrones.

Création d'un délai simple à l'aide de setTimeout

Pour créer un retard en JavaScript, la méthode standard consiste à utiliser sa méthode setTimeout . Par exemple:

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

Ceci consignera «Bonjour» sur la console, puis au bout de deux secondes «Monde!». Dans de nombreux cas, cela suffit: faites quelque chose, attendez, puis faites autre chose. Trié!

Cependant, sachez que setTimeout est une méthode asynchrone. Essayez de modifier le code précédent comme suit:

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

Il va enregistrer:

 Bonjour
Au revoir!
Monde!

En attente de choses avec setTimeout

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 utiliser setTimeout pour attendre l’apparition d’un certain élément sur une page Web:

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

  si (longueur.el) {
    // faire quelque chose avec el
  } autre {
    setTimeout (pollDOM, 300); // réessaie dans 300 millisecondes
  }
}

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 alors annuler le chronomètre (à l'aide de clearTimeout ou clearInterval ).

Si vous souhaitez en savoir plus Pour en savoir plus sur la méthode de JavaScript setTimeout veuillez consulter notre tutoriel qui contient de nombreux exemples pour vous aider à démarrer.

Le contrôle de flux en JavaScript moderne

C'est souvent le cas lors de l'écriture de JavaScript nous devons attendre que quelque chose se produise (par exemple, les données à extraire d'une API), puis réagir en réponse (par exemple, mettre à jour l'interface utilisateur pour afficher les données).

L'exemple ci-dessus utilise une fonction de rappel anonyme. à cette fin, mais si vous devez attendre que plusieurs choses se passent, la syntaxe devient rapidement assez complexe et vous vous retrouvez dans callback enfer .

Heureusement, le langage a considérablement évolué au cours des dernières années. ans et nous offre maintenant de nouvelles constructions pour éviter cela.

Par exemple e, en utilisant async attendent nous pouvons réécrire le code initial pour extraire des informations de l'API GitHub:

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

Le code s'exécute maintenant de haut en bas. L'interprète JavaScript attend que la requête réseau soit terminée et le nombre de pensions publiques est enregistré en premier, suivi du message «Hello!».

Si c'est plus le genre de chose que vous essayez d'accomplir, je vous encourage à lisez notre article Le contrôle de flux dans le JS moderne: rappels de promesses asynchrones / Await .

Amener le sommeil à un code JavaScript natif

Si vous êtes toujours avec moi, alors je suppose que vous êtes plutôt prêt pour bloquer ce fil d'exécution et faire en sorte que JavaScript attende.

Voici comment procéder:

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

console.log ("Bonjour");
sommeil (2000);
console.log ("World!");

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

. Il fonctionne en utilisant la méthode Date.now pour obtenir le nombre de millisecondes écoulées. écoulé depuis le 1 er janvier 1970 et l’attribution de cette valeur à une variable de date . Il crée ensuite une variable vide currentDate avant d'entrer une boucle à faire ... pendant que se boucle. Dans la boucle, il obtient à plusieurs reprises le nombre de millisecondes écoulées depuis le 1er janvier 1970 et attribue la valeur à la variable currentDate précédemment déclarée. La boucle continuera pendant que la différence entre date et currentDate est inférieure au délai souhaité en millisecondes.

Travail effectué, n'est-ce pas? Eh bien pas tout à fait…

Une meilleure fonction de sommeil

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 fil d'exécution de JavaScript et garantira que personne ne pourra interagir avec votre programme jusqu'à la fin. Si vous avez besoin d'un délai important, vous risquez même de tout bloquer.

Alors, que faire?

Eh bien, il est également possible de combiner les techniques apprises précédemment dans l'article pour créer une fonction de sommeil moins intrusive. :

 function sleep (ms) {
  renvoyer une nouvelle promesse (resolver => setTimeout (resol, ms));
}

console.log ("Bonjour");
sleep (2000) .then (() => {console.log ("World!");});

Ce code enregistre “Bonjour”, attendez deux secondes, puis enregistrez “Monde!” Sous le capot, nous utilisons la méthode setTimeout pour résoudre une promesse après une nombre donné de millisecondes.

Notez que nous devons utiliser un rappel puis pour vous assurer que le deuxième message est enregistré avec un délai. Nous pouvons également chaîner plus de rappels sur le premier:

 console.log ("Hello");
sommeil (2000)
  .then (() => {console.log ("World!");})
  .then (() => {
    sommeil (2000)
      .then (() => {console.log ("Au revoir!");})
    });

Cela fonctionne, mais a l'air laid. On peut se débrouiller avec async ... wait :

 function sleep (ms) {
  renvoyer une nouvelle promesse (resolver => setTimeout (resol, ms));
}

fonction asynchrone delayGreeting () {
  console.log ("Bonjour");
  attendre le sommeil (2000);
  console.log ("World!");
  attendre le sommeil (2000);
  console.log ("Au revoir!");
}

delayGreeting ();

Cela semble plus joli, mais signifie que tout code utilisant la fonction sleep doit être marqué comme async .

Voir le stylo
yLLQJrX
de SitePoint ( @SitePoint )
sur CodePen .

Bien entendu, ces deux méthodes présentent toujours l'inconvénient (ou la fonctionnalité) de ne pas avoir . ] mettre en pause l'exécution complète du programme. Seule votre fonction dort:

 function sleep (ms) {
  renvoyer une nouvelle promesse (resolver => setTimeout (resol, ms));
}

fonction asynchrone delayGreeting () {
  console.log ("Bonjour");
  attendre le sommeil (2000);
  console.log ("World!");
}

delayGreeting ();
console.log ("Au revoir!");

Le code ci-dessus enregistre ce qui suit:

 Hello
Au revoir!
Monde!

Conclusion

Les problèmes de synchronisation en JavaScript sont la cause 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'atteindre.

Bien qu'une fonction de veille soit présente dans de nombreux autres langages, Je vous encourage à adopter la nature asynchrone de JavaScript et à ne pas combattre le langage. C'est en fait assez agréable de s'y habituer.

En outre, consultez ces liens qui ont inspiré une partie du code de cet article:

Si vous avez des questions, rendez-vous à les forums de SitePoint et lancez la discussion




Source link