La réponse de Fabrício est parfaite. mais je voulais compléter sa réponse par quelque chose de moins technique, qui repose sur une analogie pour aider à expliquer le concept d'asynchronicité .
Une analogie ...
Hier, le travail que je faisais demandait des informations à un collègue. Je lui ai téléphoné; voici comment s'est déroulée la conversation:
Moi : Salut Bob, j'ai besoin de savoir comment nous avons foutu le bar la semaine dernière. Jim veut un rapport à ce sujet et vous êtes le seul à en connaître les détails.
Bob : Bien sûr, mais ça me prendra environ 30 minutes?
Moi : C'est génial Bob. Donnez-moi une bague quand vous avez l'information!
À ce stade, j'ai raccroché le téléphone. Puisque j'avais besoin des informations de Bob pour compléter mon rapport, j'ai quitté le rapport et suis allé prendre un café à la place, puis j'ai rattrapé un courrier électronique. 40 minutes plus tard (Bob est lent), Bob a rappelé et m'a donné les informations dont j'avais besoin. À ce stade, j’ai repris mon travail avec mon rapport, car j’avais toutes les informations dont j’avais besoin.
Imaginez si la conversation s'était déroulée comme ceci à la place;
Moi : Salut Bob, j'ai besoin de savoir comment nous avons foutu le bar la semaine dernière. Jim veut un rapport à ce sujet et vous êtes le seul à en connaître les détails.
Bob : Bien sûr, mais ça me prendra environ 30 minutes?
Moi : C'est génial Bob. J'attendrai.
Et je me suis assis là et a attendu. Et attendu. Et attendu. Pendant 40 minutes. Ne rien faire d'autre que d'attendre. Finalement, Bob m'a donné l'information, nous avons raccroché et j'ai complété mon rapport. Mais j'avais perdu 40 minutes de productivité.
C'est un comportement asynchrone ou synchrone
C'est exactement ce qui se passe dans tous les exemples de notre question. Charger une image, charger un fichier sur un disque et demander une page via AJAX sont des opérations lentes (dans le contexte de l'informatique moderne).
Plutôt que d’ attendre la fin de ces opérations lentes, JavaScript vous permet d’enregistrer une fonction de rappel qui sera exécutée une fois l’opération lente terminée. En attendant, JavaScript continuera à exécuter un autre code. Le fait que JavaScript exécute un autre code en attendant la fin de l'opération lente rend le comportement asynchrone . Si JavaScript avait attendu que l'opération se termine avant d'exécuter un autre code, il s'agirait d'un comportement synchrone .
var outerScopeVar;
var img = document.createElement('img');
// Here we register the callback function.
img.onload = function() {
// Code within this function will be executed once the image has loaded.
outerScopeVar = this.width;
};
// But, while the image is loading, JavaScript continues executing, and
// processes the following lines of JavaScript.
img.src = 'lolcat.png';
alert(outerScopeVar);
Dans le code ci-dessus, nous demandons à JavaScript de se charger lolcat.png
, opération qui est une opération lente . La fonction de rappel sera exécutée une fois cette opération lente effectuée, mais entre-temps, JavaScript continuera à traiter les lignes de code suivantes. c'est à dire alert(outerScopeVar)
.
C'est pourquoi nous voyons l'alerte montrant undefined
; puisque le alert()
est traité immédiatement, plutôt qu'après le chargement de l'image.
Afin de corriger notre code, tout ce que nous avons à faire est de déplacer le alert(outerScopeVar)
code dans la fonction de rappel. En conséquence, nous n’avons plus besoin de la outerScopeVar
variable déclarée comme variable globale.
var img = document.createElement('img');
img.onload = function() {
var localScopeVar = this.width;
alert(localScopeVar);
};
img.src = 'lolcat.png';
Vous verrez toujours qu'un rappel est spécifié en tant que fonction, car c'est la seule façon * de JavaScript de définir du code, mais de ne l'exécuter que plus tard.
Par conséquent, dans tous nos exemples, le function() { /* Do something */ }
est le rappel; pour corriger tous les exemples, tout ce que nous avons à faire est de déplacer le code qui nécessite la réponse de l'opération!
* Techniquement, vous pouvez eval()
aussi l' utiliser , mais eval()
c'est mal pour ce but
Comment puis-je garder mon correspondant en attente?
Vous pourriez avoir actuellement un code similaire à celui-ci;
function getWidthOfImage(src) {
var outerScopeVar;
var img = document.createElement('img');
img.onload = function() {
outerScopeVar = this.width;
};
img.src = src;
return outerScopeVar;
}
var width = getWidthOfImage('lolcat.png');
alert(width);
Cependant, nous savons maintenant que cela return outerScopeVar
se produit immédiatement; avant que la onload
fonction de rappel ait mis à jour la variable. Cela conduit à getWidthOfImage()
revenir undefined
et à undefined
être alerté.
Pour résoudre ce problème, nous devons permettre à l'appelant getWidthOfImage()
de la fonction d'enregistrer un rappel, puis de déplacer l'alerte de la largeur à l'intérieur de ce rappel.
function getWidthOfImage(src, cb) {
var img = document.createElement('img');
img.onload = function() {
cb(this.width);
};
img.src = src;
}
getWidthOfImage('lolcat.png', function (width) {
alert(width);
});
... comme précédemment, notez que nous avons pu supprimer les variables globales (dans ce cas width
).