[Les classiques du front-end] Solution JS-asynchrone

synchrone et asynchrone

Comme nous le savons tous, JavaScriptil s'agit d'un langage monothread, ce qui signifie qu'une seule tâche peut être exécutée à la fois, et la tâche suivante ne sera exécutée qu'après l'exécution de la tâche en cours. L'avantage de ce mode est que l'exécution environnement est relativement simple, mais les inconvénients sont également très évidents, une fois qu'une certaine tâche est bloquée, cela entraînera le blocage de l'ensemble du programme.Afin de résoudre ce problème, JS divise le mode d'exécution de la tâche en deux 同步(Synchronous)types 异步(Asynchronous).

Pour plus de détails sur les modes d'exécution synchrone et asynchrone, veuillez vous référer à la boucle d'événement

Parlons de plusieurs solutions pour la programmation asynchrone JS.

1. Fonction de rappel

La fonction de rappel est la méthode la plus élémentaire de programmation asynchrone, elle est généralement transmise en tant que paramètre à une autre fonction et la fonction de rappel est exécutée une fois l'exécution de la fonction parent terminée.

Par exemple:

function logB(){
    
    
    console.log("b");
}

function parent(a, callback) {
    
    
    console.log(a);
    typeof callback === 'function' ? callback() : return
}

parent('a', logB)

Dans l'exemple ci-dessus, dans parentla fonction, si le paramètre de rappel est passé à une fonction, la fonction asera exécutée après la sortie du paramètre formel callback. Dans l'exemple ci-dessus, logB est passé au parent en tant que fonction de rappel et exécuté

Dans le processus de développement actuel, il existe encore de nombreux scénarios d'utilisation de la fonction de rappel, tels que la méthode de traversée de tableau commune forEach, dont le premier paramètre est la fonction de rappel

let arr = [1, 2, 3]
arr.forEach((item) => {
    
    
    console.log(item);
})

L'avantage de la fonction callback est qu'elle est simple et facile à comprendre, mais en fait, une fois imbriquée, elle n'est pas propice à la maintenance et à la lisibilité du code. De plus, le couplage élevé entre les différentes parties rend le processus déroutant. Le plus classique est. Dans le processus de développement proprement dit 回调地狱(callback hell),
souvent Certaines entreprises doivent d'abord envoyer une demande pour obtenir des données, puis envoyer une deuxième demande en fonction du résultat de retour de cette demande. La troisième demande peut nécessiter le résultat de retour de la deuxième requête en paramètre, donc imbriquée couche par couche Cela dit 回调地狱, un tel code est difficile à maintenir.

ajax('url1', (res1) => {
    
    
    console.log(res1)
    ajax('url2+res1', (res2) => {
    
    
        console.log(res2)
        ajax('url3 + res2', (res) => {
    
    
            console.log(res3)
            ...
        })
    })
})

Avantages : simple et facile à comprendre
Inconvénients : lorsque les fonctions de rappel multicouches sont imbriquées, il est facile de confondre, ce qui n'est pas propice à la maintenance et à la lisibilité du code, et est facile à écrire回调地狱

écouteur d'événement

Ainsi, l'exécution des tâches asynchrones ne dépend pas de l'ordre d'exécution du code, mais de la survenance d'un événement.

element.addEventListener('click', ()=> {
    
    
    console.log('click')
})

La signification de l'exemple ci-dessus est que lorsque elementvous cliquez dessus, il afficheraclick

  • Avantages : il est relativement facile à comprendre et plusieurs événements peuvent être liés, et chaque événement peut spécifier plusieurs fonctions de rappel, ce qui peut être relativement bon 去耦合et propice à la réalisation de la modularisation.
  • Inconvénients : l'ensemble du programme devient événementiel, le processus en cours d'exécution est très flou, il est difficile de voir le processus principal et la lisibilité du code est faible

Promesse

Promiseest un moyen de gérer le code asynchrone (et de ne pas tomber dans l'enfer des rappels)

PromiseReprésente une opération asynchrone, qui a trois états pending(进行中), fulfilled(已完成), rejected(已失败), un Promiseobjet doit être dans l'un de ces trois états

  • pending: Etat initial, ni achevé ni rejeté
  • fulfilled: L'opération s'est bien déroulée
  • rejected: l'opération a échoué

Lorsqu'il est Promiseappelé, il pendingcommencera par, le code continuera à s'exécuter, mais Promisetoujours dans pendingl'état, jusqu'à ce que l'exécution soit terminée, il se terminera par fulfilledou rejected, et il sera transmis à la fonction de rappel en conséquence - thenou catch.
Avantages : non seulement peut résoudre le problème de l'enfer des rappels, et peut détecter les erreurs et les gérer
Inconvénients : la promesse ne peut pas être annulée

Générateur

GeneratorFunction est une solution de programmation asynchrone fournie par ES6. Son comportement grammatical est complètement différent des fonctions traditionnelles. La Generatorprincipale caractéristique est qu'il peut contrôler l'exécution des fonctions.

Grammaticalement, on peut d'abord comprendre qu'une Generatorfonction est une machine à états qui encapsule plusieurs états internes.
GeneratorEn plus de la machine d'état, la fonction est également une fonction de génération d'objet traversant.
La fonction peut être suspendue, yield peut être suspendu et la méthode suivante peut être démarrée, et le résultat de l'expression après yield est renvoyé à chaque fois.
L'expression yield elle-même n'a pas de valeur de retour, ou elle retourne toujours undefined. La méthode suivante peut prendre un paramètre, qui sera utilisé comme valeur de retour de l'expression de rendement précédente.

asynchrone/attendre

Essentiellement, async et await sont du sucre syntaxique pour Promise, ce qui peut faire ressembler le code asynchrone à du code synchrone.

Pour une promesse plus détaillée, veuillez vous référer à : Promesse

Résumer

  1. Historique de l'évolution de la programmation asynchrone JS : callbackpromisegeneratorasync/await
  2. async/awaitLa réalisation de la fonction consiste à envelopper Generatorla fonction et l'exécuteur automatique dans une fonction.
  3. async/awaitOn peut dire que c'est la solution asynchrone ultime.

(1) async/awaitPar rapport à la fonction Promise, les avantages se traduisent par :

  • Gérer la chaîne d'appels puis écrire du code plus clairement et plus précisément
  • Et cela peut également résoudre avec élégance le problème de l'enfer des rappels.
    Bien sûr, async/awaitles fonctions ont aussi quelques inconvénients :
  • awaitParce que le code asynchrone est transformé en un code synchrone, si plusieurs codes asynchrones n'ont pas de dépendances mais que l'utilisation awaitentraînera une dégradation des performances, si le code n'a pas de dépendances, il est tout à fait possible d'utiliser Promise.allla méthode.

(2) async/awaitL'amélioration de la fonction vers la fonction Générateur se traduit par les trois points suivants :

  1. Actionneur intégré.

    L'exécution de la fonction Generator doit s'appuyer sur l'exécuteur, il existe donc une bibliothèque de fonctions co et la fonction async est livrée avec un exécuteur. En d'autres termes, l'exécution d'une fonction asynchrone est exactement la même que celle d'une fonction normale, avec une seule ligne.

  2. Applicabilité plus large.

    La bibliothèque de fonctions co convient que la commande yield ne peut être suivie que d'une fonction Thunk ou d'un objet Promise, tandis que la commande await d'une fonction asynchrone peut être suivie d'un objet Promise et de valeurs de type primitif (chiffres, chaînes et valeurs booléennes , mais cela équivaut à une opération synchrone).

  3. Meilleure sémantique.

    async et await ont une sémantique plus claire que les astérisques et le rendement. async indique qu'il y a une opération asynchrone dans la fonction, et await indique que l'expression suivante doit attendre le résultat.

おすすめ

転載: blog.csdn.net/achen0511/article/details/130443808