Почему моя переменная не изменяется после модификации внутри функции? - Ссылка на асинхронный код
У меня возникла проблема, и я не понимаю, почему в следующих примерах переменная outerScopeVar
всегда оказывается неопределенной. Вот сами примеры:
var outerScopeVar;
var img = document.createElement('img');
img.onload = function() {
outerScopeVar = this.width;
};
img.src = 'lolcat.png';
alert(outerScopeVar);
var outerScopeVar;
setTimeout(function() {
outerScopeVar = 'Hello Asynchronous World!';
}, 0);
alert(outerScopeVar);
// Пример с использованием jQuery
var outerScopeVar;
$.post('loldog', function(response) {
outerScopeVar = response;
});
alert(outerScopeVar);
// Пример в Node.js
var outerScopeVar;
fs.readFile('./catdog.html', function(err, data) {
outerScopeVar = data;
});
console.log(outerScopeVar);
// Пример с использованием промисов
var outerScopeVar;
myPromise.then(function(response) {
outerScopeVar = response;
});
console.log(outerScopeVar);
// Пример с использованием обсерваблов
var outerScopeVar;
myObservable.subscribe(function(value) {
outerScopeVar = value;
});
console.log(outerScopeVar);
// Пример с API геолокации
var outerScopeVar;
navigator.geolocation.getCurrentPosition(function(pos) {
outerScopeVar = pos;
});
console.log(outerScopeVar);
Почему в этих примерах выводится undefined
? Мне не интересуют обходные пути, я хочу понять почему это происходит.
Примечание: Этот вопрос является каноническим для темы асинхронности в JavaScript. Пожалуйста, улучшайте этот вопрос и добавляйте более простые примеры, с которыми может ассоциироваться сообщество.
1 ответ(ов)
Другие ответы отличные, и я просто хочу дать простой ответ на этот вопрос, ограничиваясь асинхронными вызовами jQuery.
Все вызовы ajax (включая $.get
, $.post
и $.ajax
) являются асинхронными.
Рассмотрим ваш пример:
var outerScopeVar; // строка 1
$.post('loldog', function(response) { // строка 2
outerScopeVar = response;
});
alert(outerScopeVar); // строка 3
Выполнение кода начинается с первой строки, где объявляется переменная, и на второй строке инициируется асинхронный вызов (т.е. POST-запрос). Код продолжает выполняться на третьей строке, не дожидаясь завершения выполнения POST-запроса.
Предположим, что выполнение POST-запроса занимает 10 секунд. Значение переменной outerScopeVar
будет установлено только после этих 10 секунд.
Для проверки:
var outerScopeVar; // строка 1
$.post('loldog', function(response) { // строка 2, занимает 10 секунд
outerScopeVar = response;
});
alert("Давайте подождем немного! Ждать - это интересно"); // строка 3
alert(outerScopeVar); // строка 4
Теперь, когда вы выполните этот код, на третьей строке появится оповещение. Подождите некоторое время, пока вы не убедитесь, что POST-запрос вернул какое-то значение. Затем, когда вы нажмете "ОК" в окне оповещения, следующее оповещение будет выводить ожидаемое значение, потому что вы подождали.
В реальной ситуации код будет выглядеть так:
var outerScopeVar;
$.post('loldog', function(response) {
outerScopeVar = response;
alert(outerScopeVar);
});
Весь код, который зависит от асинхронных вызовов, перемещается внутрь асинхронного блока или ждет завершения асинхронных вызовов.
Как вернуть ответ от асинхронного вызова?
Как загружать файлы асинхронно с помощью jQuery?
Как заставить jQuery выполнять синхронный запрос Ajax вместо асинхронного?
Существует ли ссылка на "последнюю" библиотеку jQuery в Google APIs?
Как создать диалог с кнопками "Ок" и "Отмена"