9

Почему моя переменная не изменяется после модификации внутри функции? - Ссылка на асинхронный код

5

У меня возникла проблема, и я не понимаю, почему в следующих примерах переменная 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 ответ(ов)

0

Другие ответы отличные, и я просто хочу дать простой ответ на этот вопрос, ограничиваясь асинхронными вызовами 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);
});

Весь код, который зависит от асинхронных вызовов, перемещается внутрь асинхронного блока или ждет завершения асинхронных вызовов.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь