1
votes

Processus d'exécution d'exécution de la fonction

Je me demandais comment le code ci-dessous sera exécuté lors de l'exécution. Je suis conscient que les événements sont gérés par l'API du navigateur et sont donc sortis de la pile d'appels. Et puis les rappels sont enregistrés dans la file d'attente par l'API. Et puis ces messages sont exécutés une fois que la pile est vide.

Mais cela arrive quand il y a plusieurs fonctions dans la fonction de rappel onclick. Avoir à la fois des fonctions séquentielles et asynchrones. Puis vont-ils à nouveau repousser l'API du navigateur de la pile de la file d'attente à l'appel, puis de nouveau l'API du navigateur?

Comment tout le code ci-dessous est exécuté?

$('#test').on(click, function() {
   console.log('start');

   //modifies the dom like add div in the html
   modifyDom();

   //http ajax call
   someAjaxCall();

   while(let i < 5) {
      console.log(i);
      i++
   }

   setTimeout(function(){ console.log('Zero Delay'); },0);


});


3 commentaires

Vous devez utiliser les promesses pour attendre l'appel asynchrone.


Vous avez fait une faute de frappe: vous écrivez function au lieu de function dans setTimeout (function () {console.log ('Zero Delay');}, 0);


@SLaks oui je sais mais je me demandais comment tout le processus est exécuté.


3 Réponses :


-2
votes

Après avoir cliqué sur #test , vous aurez:

  1. console.log ('start'); exécuté directement après la saisie du rappel
  2. modifyDom () est le suivant. Il est également exécuté de manière synchrone.
  3. someAjaxCall (); . Ici, la requête sera envoyée directement, puis son propre rappel gérera la réponse quand il la recevra finalement (asynchrone)
  4. tandis que la boucle s'exécute de manière synchrone
  5. setTimeout Bien que cela fonctionne normalement de manière asynchrone (après un certain délai), vous avez attribué un délai de 0. Il fonctionnera donc directement après l'avoir appelé.

0 commentaires

0
votes

ajoutons des numéros de ligne pour suivre l'exécution

01 $('#test').on(click, function() {
02    console.log('start');
03 
04    modifyDom();
05 
06    someAjaxCall();
07 
08    while(let i < 5) {
09       console.log(i);
10       i++;
11    }
12 
13    setTimeout(
14       function(){
15          console.log('Zero Delay');
16       },
17       0
18    );
19 });
  1. 01 : attache le gestionnaire d'événements
  2. attendez clic ...
  3. cliquer
  4. 02 : imprimer 'start' sur la console
  5. 04 : effectuer des manipulations DOM
  6. 06 : envoyez la requête ajax et attendez la réponse sur le thread réseau (pas le thread principal)
  7. 08-11
    1. i vaut 0
    2. i vaut 1
    3. i vaut 2
    4. i vaut 3
    5. i vaut 4
  8. 13-18 : ajoutez un rappel 14-16 au thread du minuteur (pas au thread principal)
  9. attendre que les threads retournent le contrôle ...

maintenant, tout ce qui suit peut se produire:

  1. ajax et / ou timeout "return" avant de terminer les exécutions précédentes
  2. ajax "return" avant expiration du délai
  3. timeout "return" avant ajax

dans le cas 1, le thread principal ne se soucie pas du tout de ce "retourné" puisqu'il s'agit d'une seule pile continue d'instructions synchrones. cela signifie que le cas 1 se résout finalement aux cas 2 et 3

dans les cas 2 et 3, puisque les microtâches de promesse ont la priorité sur les threads de minuterie, ajax "return" est promis en premier, puis le rappel du délai d'expiration se produit p >


Modifier 1

Je recommande vivement de regarder cette conférence sur le thème des bases de la boucle d'événements et au-delà, car elle explique l'interaction du code de synchronisation, des minuteries, des promesses et bien plus encore


0 commentaires

0
votes

Ce que vous avez dit sur les piles d'appels et les files d'attente est correct. JavaScript exécutera tout le code synchrone et ajoutera des appels asynchrones dans une file d'attente. Le setTimeout déclare quand il peut être exécuté à l'avance. S'il n'y a pas de tâches en attente dans la file d'attente, elle sera appelée après que la pile d'appels ait été effacée au temps minimum prévu, qui dans ce cas est égal à zéro. L'argument delay pour setTimeout ne garantit pas que cela s'exécutera à ce moment-là, mais est une valeur minimale pour quand c'est possible. Ceci est dû au fait que les éléments existants dans la file d'attente doivent d'abord être effacés avant que cela puisse être traité.

Les gestionnaires d'événements pour les appels réseau, comme votre fonction someAjaxCall , sont également des rappels. Les écouteurs de l'appel Ajax sont essentiellement en attente et ne sont pas ajoutés à la file d'attente jusqu'à ce que l'événement pertinent se produise (comme progress , error ou success ) . Pourtant, ils sont exactement les mêmes que setTimeout et déclencheront un rappel dans la file d'attente.

Une chose qui pourrait aider à clarifier un peu cela est le code async > et attendent la syntaxe. En déclarant votre fonction asynchrone, vous pouvez mieux gérer les tâches asynchrones dans votre flux de travail. Par exemple, si vous avez besoin de traiter votre appel Ajax avant de continuer, vous pouvez faire quelque chose comme ceci:

// start
// either 'data!', with the {response} or 'network error!', with the {error}
// 1
// 2
// 3
// 4
// 5
/*
    call stack has ended
    the function will return undefined because there is nothing being returned
    all queues are assessed from oldest to youngest.
    only the setTimeout is in the queue so it's callback is executed
*/
//'Zero Delay'

Dans cet exemple, la fonction while attend la réponse de someAjaxCall dans un bloc try / catch. L'exécution du reste de la fonction est retardée jusqu'à ce que cette fonction soit résolue ou rejetée. Avec cette configuration, vous verrez cette déconnexion:

// declaring function with async tag
$('#test').on(click, async function() {
   console.log('start');

   //modifies the dom like add div in the html
   modifyDom();

   //http ajax call
   try {
       let response = await someAjaxCall(); 
       console.log('data!', response);
   } catch(err){
       console.log('network error!', err);
   }


   while(let i < 5) {
      console.log(i);
      i++
   }

   setTimeout(function(){ console.log('Zero Delay'); },0);


});

function someAjaxCall(){
    return new Promise((resolve, reject) => {
       $.ajax({
           url:'someUrl',
           type:'GET',
           success:function(response){
               resolve(response); 
           },
           error:function(err){
               reject(err);
           }
       })
    })
}

Mettre à jour

De plus, si vous avez besoin de mesurer le temps de votre fonction prend pour exécuter vous pouvez utiliser console.time et console.timeEnd (documentation ici ). En ajoutant console.time avec une étiquette, comme console.time ('Click time') au début de votre fonction, vous pouvez ajouter console.timeEnd ( 'Click time') dans une autre position pour voir exactement combien de temps il a fallu pour courir entre ces points (comme depuis le début de la fonction de clic jusqu'au rappel de setTimeout ). p>


0 commentaires