JS asynchrone: principe d'exécution et rappel



1. Le principe de l'exécution asynchrone JS

  Nous savons que JavaScript est monothread , tandis que les navigateurs sont multithreads . Les tâches d'exécution à un seul thread doivent être mises en file d'attente une par une. Si une tâche prend beaucoup de temps à s'exécuter (comme ajax prend beaucoup de temps), elle n'entraînera directement aucune réponse et les tâches suivantes attendaient d'être exécutées. À ce stade, vous devez utiliser l'asynchronie.

  Pour comprendre asynchronisme, il faut d' abord savoir que les navigateurs ont trois fils résidents de base: fil de moteur JS , fil de déclenchement de l' événement , et GUI fil de rendu .

  Le thread du moteur JS et le thread de déclenchement d'événements constituent ensemble un mécanisme de boucle d'événements , et le thread de rendu de l'interface graphique et le moteur JS s'excluent mutuellement. Lorsque le moteur JS est exécuté, le thread GUI est suspendu et les mises à jour de l'interface graphique sont stockées dans une file d'attente. Lorsque le moteur JS est inactif, il est exécuté immédiatement.

  Nous analysons à partir de son mécanisme de boucle d'événements: Insérez la description de l'image ici
  les threads du moteur JS sont divisés en tâches synchrones et asynchrones:

    1. Toutes les tâches de synchronisation sont exécutées via le thread principal pour former une pile d'exécution .
    2. Lorsqu'il existe une tâche asynchrone, remettez-la au processus asynchrone (WebAPI): y compris le thread de déclenchement d'événement ou le traitement du thread du minuteur pour former une file d'attente de tâches .
    3. Lorsque toutes les tâches de la pile d'exécution sont traitées et que le thread principal est inactif, les tâches sont extraites de la file d'attente des tâches vers la pile d'exécution pour exécution.

  En termes simples, en plus du thread principal, JavaScript a également une file d'attente de tâches. La file d'attente de tâches stocke le contenu qui doit être exécuté de manière asynchrone. Une fois le thread principal exécuté, il continuera à analyser et à exécuter les tâches de la file d'attente des tâches. jusqu'à ce que la file d'attente soit vidée.

Dessiner la solution:


Insérez la description de l'image ici

  Comme le montre l'image, Xiaoming ne pourra pas jouer au jeu DNF si l'apprentissage prend beaucoup de temps, il met donc l'apprentissage dans la file d'attente des tâches asynchrones, puis apprend (file d'attente des tâches) après avoir joué au jeu (fil principal) . Au cours de la période, la mère a ajouté des événements d'apprentissage (événements DOM) et Xiaoming a vérifié quelles étaient les autres tâches (analyse cyclique) chaque fois que Xiaoming terminait une tâche d'apprentissage, jusqu'à l'achèvement final.


  Regardons un autre exemple (le navigateur s'actualise et continue de cliquer sur le bouton):

      let myData = null
      //ajax请求
      function ajax() {
    
    
      //腾讯新冠实时数据接口,仅做学习
        axios.get('https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=chinaDayList,chinaDayAddList,nowConfirmStatis,provinceCompare')
          .then(data => {
    
    
            console.log("ajax返回成功");
            myData = data.data
            console.log(myData);

          })
          .catch(error => {
    
    
            console.log("ajax返回失败");
          })
      }
      console.log(myData);
      ajax()
      setTimeout(() => {
    
    
        console.log('定时器');
      }, 2000);
      console.log(myData);
      const btn = document.querySelector('button')
      btn.onclick = () => {
    
    
        console.log("点击了");
      }

null
null
ajax retourne le succès
Objet
cliqué
Minuterie
cliquée

  On peut voir que la console est exécutée de manière synchrone dans le thread principal et exécutée en premier, tandis que la file d'attente des tâches en dehors du thread principal stocke le contenu de l'exécution asynchrone. Voici les événements setTimeout, ajax et DOM, qui sont exécutés dans l'ordre du file d'attente de tâches ( file d'attente d' analyse cyclique) .
  
  Pourquoi voulez-vous scanner en boucle?

  Il peut être vu à partir de l'événement de clic que lorsque l'utilisateur interagit (événement de clic, événement de défilement, événement de changement de taille de fenêtre, etc.), de nouveaux événements seront ajoutés à la file d'attente des tâches dans la boucle d'événements, puis attendront l'exécution, donc un balayage cyclique est nécessaire.

Deux, rappels dans JS asynchrones


  L'asynchronie étant exécutée dans la dernière file d'attente de tâches, une grande partie de notre logique est difficile à implémenter. Pour le moment, nous devons gérer cette logique asynchrone. La méthode la plus couramment utilisée est le callback -call back.

Fonction de rappel: En termes simples, lorsque la fonction A est passée dans la fonction B en tant que paramètre, la fonction B est la fonction de rappel exécutée par la fonction A. Il existe deux types de rappels: les rappels imbriqués et les rappels chaînés.


  Voici une utilisation simple du callback:

      let myData = null
      console.log(myData);
      setTimeout(() => {
    
    
        console.log('定时器');
      }, 2000);
      const btn = document.querySelector('button')
      btn.onclick = () => {
    
    
        console.log("点击了");
      }
      let name = "张三"
      function hr(callback) {
    
    
        setTimeout(() => {
    
    
          console.log(`我是${
      
      name}`);
          callback();
        }, 2001);
      }
      console.log(myData);
      function gj() {
    
    
        console.log(`${
      
      name}你好,我是李四,认识一下吧`);
      }
      hr(gj)

null
null
cliqué
minuterie
Je m'appelle Zhang
San Zhang San Bonjour, je m'appelle Li Si, apprenons à savoir que vous avez
cliqué

  Évidemment, nous utilisons des rappels lorsque nos fonctions ont besoin de données, et des rappels asynchrones sont utilisés ici.

  Bien que le callback soit une méthode courante pour résoudre les problèmes asynchrones, il s'accompagne des besoins de plus en plus complexes de JS. Synchrone et asynchrone nécessitent de plus en plus de logique d'implémentation de rappel. Le mélange d'imbrication et d'indentation de rappel synchrone et asynchrone et excessive rend le code difficile à interpréter et à maintenir, formant un «enfer de rappel» .

Insérez la description de l'image ici

  Regardons un exemple:

const verifyUser = function(username, password, callback){
    
    
   dataBase.verifyUser(username, password, (error, userInfo) => {
    
    
       if (error) {
    
    
           callback(error)
       }else{
    
    
           dataBase.getRoles(username, (error, roles) => {
    
    
               if (error){
    
    
                   callback(error)
               }else {
    
    
                   dataBase.logAccess(username, (error) => {
    
    
                       if (error){
    
    
                           callback(error);
                       }else{
    
    
                           callback(null, userInfo, roles);
                       }
                   })
               }
           })
       }
   })
};

La plupart des gens ne voient que le code ci-dessus et sentent le goût de leur cerveau se figer. S'il y a des centaines de blocs de code de ce type dans un projet, après un certain temps, je crois que même ceux qui l'ont écrit auront mal à la tête. Venir à son propre projet, c'est comme venir en enfer.

  La chose la plus importante est qu'en même temps, le rappel a toujours un problème de confiance , et il donne le contrôle d'exécution à un tiers (comme ajax). Afin de résoudre le problème de confiance, nous devons écrire diverses logiques dans le programme pour résoudre le problème de confiance causé par les rappels.
  · L'appel est trop tôt
  · L'appel est terminé
  · Le nombre d'appels est trop ou trop faible et les paramètres requis ne sont pas transmis avec succès à la fonction de rappel
  · Les erreurs éventuelles sont avalées.

  Il peut être constaté que l'écriture d'une logique spécifique pour résoudre des problèmes de confiance spécifiques l'a rendue plus difficile que sa propre valeur d'application, et cela causera également des problèmes tels que la redondance du code et une mauvaise lisibilité.


  Pour résumer: Les rappels résolvent les défauts de l'asynchrone:
     1) Il n'est pas conforme à la pensée logique du traitement des tâches des gens
     2) Le problème de confiance causé par les rappels.


  Face aux inconvénients de plus en plus évidents des callbacks, ES6 a mis à jour Promises pour résoudre les problèmes asynchrones. Le prochain article écrit ES6-Promise.

Je suppose que tu aimes

Origine blog.csdn.net/Zxinxxx/article/details/114444890
conseillé
Classement