异步流控

Contributeurs
Table des matières
N'oubliez pas que ce contenu est une référence et qu'il peut être rapidement dépassé. Nous recommandons d'autres sources telles que MDN.

Le contenu de cet article est fortement inspiré par Mixu's Node.js Book.

À la base, JavaScript est conçu pour être non bloquant sur le thread "principal", c'est-à-dire là où les vues sont rendues. Vous pouvez imaginer l'importance de cet aspect dans le navigateur. Lorsque le fil d'exécution principal est bloqué, cela entraîne le fameux "freezing" que les utilisateurs finaux redoutent, et aucun autre événement ne peut être envoyé, ce qui entraîne la perte de l'acquisition de données, par exemple.

Cela crée des contraintes uniques que seul un style de programmation fonctionnel peut résoudre. C'est là que les callbacks entrent en jeu.

Cependant, les callbacks peuvent devenir difficiles à gérer dans des procédures plus complexes. Il en résulte souvent un "enfer de callbacks", où de multiples fonctions imbriquées avec des callbacks rendent le code plus difficile à lire, à déboguer, à organiser, etc.

JS

Bien sûr, dans la vie réelle, il y aurait très probablement des lignes de code supplémentaires pour gérer result1, result2, etc., ainsi, la longueur et la complexité de cette question aboutissent généralement à un code qui a l'air beaucoup plus désordonné que l'exemple ci-dessus.

C'est là que les fonctions sont d'une grande utilité. Les opérations plus complexes sont composées de nombreuses fonctions :

  1. initiator style / input
  2. middleware
  3. terminator

Le "initiator style / input" est la première fonction de la séquence. Cette fonction accepte l'entrée originale, le cas échéant, de l'opération. L'opération est une série de fonctions exécutables, et l'entrée originale sera principalement :

  1. les variables dans un environnement global
  2. invocation directe avec ou sans arguments
  3. valeurs obtenues par des requêtes du système de fichiers ou du réseau

Les demandes du réseau peuvent être des demandes entrantes initiées par un réseau étranger, par une autre application sur le même réseau, ou par l'application elle-même sur le même réseau ou sur un réseau étranger.

Une fonction intermédiaire renverra une autre fonction, et une fonction de terminaison invoquera le rappel. L'exemple suivant illustre le flux des demandes de réseau ou de système de fichiers. Ici, la latence est de 0 car toutes ces valeurs sont disponibles en mémoire.

JS

Gestion des États

Les fonctions peuvent être dépendantes ou non de l'état. Il y a dépendance d'état lorsque l'entrée ou une autre variable d'une fonction dépend d'une fonction extérieure.

Ainsi, il existe deux stratégies principales pour la gestion des États :

  1. en passant directement des variables à une fonction, et
  2. l'acquisition d'une valeur variable à partir d'un cache, d'une session, d'un fichier, d'une base de données, d'un réseau ou d'une autre source extérieure.

Notez que je n'ai pas mentionné de variable globale. La gestion de l'état avec des variables globales est souvent un anti-modèle bâclé qui rend difficile ou impossible la garantie de l'état. Les variables globales dans les programmes complexes doivent être évitées autant que possible.

Flux de contrôle

Si un objet est disponible en mémoire, l'itération est possible, et il n'y aura pas de modification du flux de contrôle :

JS

Cependant, si les données existent en dehors de la mémoire, l'itération ne fonctionnera plus :

JS

Pourquoi cela s'est-il produit ? setTimeout indique au CPU de stocker les instructions ailleurs sur le bus, et indique que les données sont prévues pour être récupérées à un moment ultérieur. Des milliers de cycles CPU s'écoulent avant que la fonction ne frappe à nouveau à la marque de 0 milliseconde, le CPU va chercher les instructions sur le bus et les exécute. Le seul problème est que le morceau ('') a été renvoyé des milliers de cycles auparavant.

La même situation se présente lorsqu'on traite des systèmes de fichiers et des requêtes réseau. Le thread principal ne peut tout simplement pas être bloqué pendant une période de temps indéterminée. Par conséquent, nous utilisons des callbacks pour planifier l'exécution du code dans le temps de manière contrôlée.

Vous pourrez effectuer la quasi-totalité de vos opérations avec les 3 modèles suivants :

  1. En série : les fonctions seront exécutées dans un ordre séquentiel strict, celui-ci est le plus similaire aux boucles for.

    JS
  2. Parallèle complet : lorsque la commande n'est pas un problème, comme l'envoi d'un courriel à une liste de 1 000 000 de destinataires.

    JS
  3. Parallèle limité : parallèle avec limite, comme réussir à envoyer un courriel à 1 000 000 de destinataires à partir d'une liste de 10E7 utilisateurs.

    JS

Chacune a ses propres cas d'utilisation, avantages et problèmes que vous pouvez expérimenter et lire plus en détail. Mais surtout, n'oubliez pas de modulariser vos opérations et d'utiliser des callbacks ! Si vous avez le moindre doute, traitez tout comme s'il s'agissait d'un intergiciel !