Fabrício la réponse est sur place; mais j'ai voulu compléter sa réponse avec quelque chose de moins technique, qui met l'accent sur une analogie pour expliquer le concept de l'asynchronicité.
Une Analogie...
Hier, le travail que je faisais besoin de quelques informations de la part d'un collègue de la mine. J'ai sonné à lui; voici comment la conversation se poursuivit:
Moi: Salut Bob, j'ai besoin de savoir comment nous foo'd le bar'le d de la semaine dernière. Jim veut un rapport sur elle, et vous êtes le seul qui connaît les détails autour d'elle.
Bob: bien Sûr, mais ça va me prendre environ 30 minutes?
Moi: C'est grand Bob. Donnez-moi un anneau en arrière quand vous avez obtenu les informations!
À ce stade, j'ai raccroché le téléphone. Depuis que j'ai besoin d'informations de Bob pour compléter mon rapport, j'ai quitté le rapport et est allé pour un café de la place, alors je me suis rattrapé sur certains e-mail. 40 minutes plus tard (Bob est lent), Bob rappelé et m'a donné les renseignements dont j'avais besoin. À ce stade, j'ai repris mon travail avec mon rapport, que j'ai eu toutes les informations dont j'avais besoin.
Imaginez si la conversation avait disparu comme cela à la place;
Moi: Salut Bob, j'ai besoin de savoir comment nous foo'd le bar'le d de la semaine dernière. Jim veut un rapport sur elle, et vous êtes le seul qui connaît les détails autour d'elle.
Bob: bien Sûr, mais ça va me prendre environ 30 minutes?
Moi: C'est grand Bob. Je vais attendre.
Et je me suis assis et a attendu. Et attendu. Et attendu. Pendant 40 minutes. Ne rien faire, mais en attente. Finalement, Bob m'a donné l'information, nous avons accroché, et j'ai terminé mon rapport. Mais j'avais perdu 40 minutes de la productivité.
Bienvenue à vs asynchrone synchrone comportement
C'est exactement ce qui se passe dans tous les exemples de notre question. Chargement d'une image, le chargement d'un fichier du disque, et la demande d'une page via AJAX sont toutes les opérations lentes (dans le contexte de l'informatique moderne).
Plutôt que d'attente pour ces opérations pour terminer, JavaScript vous permet de vous inscrire à un rappel qui s'exécute lorsque l'opération est terminée. Dans l'intervalle, le moteur JavaScript s'en va et fait quelque chose d'autre. Ceci est appelé asynchrone comportement. Si JavaScript avait attendu autour, cela aurait été synchrone comportement.
Laissez la carte de notre analogie à l'un des exemples de la question:
// This is my report. It needs completing
var outerScopeVar;
// This is where I make the phone call to Bob
var img = document.createElement('img');
// This is where I ask him for the information
img.src = 'lolcat.png';
// This is where I ask him to ring me back
img.onload = function() {
// And when he rings me back, I will do:
// complete my report with the information I got now
outerScopeVar = this.width;
};
// But in the meantime, I go and get some coffee. "alert(outerScopeVar);"
// shouldn't be here; this is what is causing the problem with our code.
// We'll fix that below.
alert(outerScopeVar);
Remarque, j'ai déménagé img.src = 'lolcat.png'
jusqu'en quelques lignes, d'où il était dans la question. C'est juste pour l'histoire fait sens... ça marchera parfaitement bien là où il était!
Retour à la question initiale...
Si vous regardez l'exemple de code ci-dessus, vous verrez notre alert(outerScopeVar)
est dans la partie du code qui se produit immédiatement. C'est pourquoi il n'affiche pas la bonne valeur, car la valeur n'a pas encore été reçue! C'est comme donner Jim la feuille vide juste après avoir raccroché, avant que Bob me rappelle.
Tout ce que nous devons faire, c'est de passer le code dans la fonction de rappel;
var outerScopeVar;
var img = document.createElement('img');
img.onload = function() {
outerScopeVar = this.width;
alert(outerScopeVar);
};
img.src = 'lolcat.png';
Vous aurez toujours voir un rappel étant précisé en tant que fonction, parce que c'est la seule* moyen en JavaScript pour définir un code, mais pas l'exécuter jusqu'à ce que plus tard.
Dans tous nos exemples, l' function() { /* Do something */ }
est le rappel; déplacer le code qui a besoin de la réponse de l'opération en il y!
Vous remarquerez également, il y a maintenant pas besoin d' outerScopeVar
déclarée comme une variable globale. Votre code peut devenir:
var img = document.createElement('img');
img.onload = function() {
var localScopeVar = this.width;
alert(localScopeVar);
};
img.src = 'lolcat.png';
* Techniquement, vous pouvez utiliser eval()
, mais eval()
est le mal dans ce but
Mais j'ai Jim attente pour moi de terminer le rapport. Comment puis-je le garder en attente?
Vous pourriez avoir quelque chose comme ceci pour le moment:
function goAndCreateAReportPlease(onWhat) {
var outerScopeVar;
var img = document.createElement('img');
img.onload = function() {
outerScopeVar = this.width;
};
img.src = 'lolcat.png';
return outerScopeVar;
}
var report = goAndCreateAReportPlease('how did we foo the bar?');
alert(report);
Cependant, nous savons maintenant que l' return outerScopeVar
arrive immédiatement; avant, nous avons eu de la chance pour obtenir les données de Bob. Jim est un rapport incomplet, et n'est pas heureux.
Eh bien, Jim ne veut pas attendre par mon bureau pour moi pour moi de terminer un rapport. Il m'a demandé de le faire, et m'a dit de l'appeler en arrière une fois qu'il a été fait.
Son familier?
C'est vrai... nous avons besoin pour permettre à Jim pour enregistrer un rappel, afin que nous puissions lui dire une fois que le rapport est terminé.
function goAndCreateAReportPlease(onWhat, callback) {
var img = document.createElement('img');
// Here's where I'm telling Bob to call me back once he's got the information
img.onload = function() {
// This is where I complete my report once I've got my information,
// and then call back Jim once I've done.
callback(this.width);
};
// Here's where I'm telling Bob the information I need.
img.src = 'lolcat.png';
}
// Jim asks me to create a report. He passes his callback as a second parameter
goAndCreateAReportPlease('how did we foo the bar?', function (report) {
// This is where I'm ringing him with the report.
alert(report);
});
// In the meantime, Jim can go and do something else.