→ Для более общего объяснения асинхронного поведения на разных примерах см. Почему моя переменная не изменяется после того, как я изменил ее внутри функции? - асинхронная ссылка на код
→ Если вы уже поняли проблему, перейдите к возможным решениям ниже.
Проблема
В Ajax означает асинхронный . Это означает, что отправка запроса (или, вернее, получение ответа) исключается из обычного потока выполнения. В вашем примере сразу возвращается, и следующий оператор, выполняется до того, как функция, которую вы передали в качестве обратного вызова, даже была вызвана.$.ajax
return result;
success
Вот аналогия, которая, надо надеяться, проясняет разницу между синхронным и асинхронным потоком:
синхронный
Представьте, что вы позвонили другу и попросили его найти что-то для вас. Хотя это может занять некоторое время, вы ждете по телефону и смотрите в пространство, пока ваш друг не даст вам ответ, который вам нужен.
То же самое происходит, когда вы делаете вызов функции, содержащий «нормальный» код:
function findItem() {
var item;
while(item_not_found) {
// search
}
return item;
}
var item = findItem();
// Do something with item
doSomethingElse();
Несмотря на то, что выполнение findItem
может занять много времени, любой следующий код var item = findItem();
должен ждать, пока функция вернет результат.
Асинхронный
Вы звоните своему другу снова по той же причине. Но на этот раз вы говорите ему, что спешите, и он должен перезвонить вам на ваш мобильный телефон. Вы вешаете трубку, выходите из дома и делаете все, что планировали. Как только ваш друг перезвонит вам, вы будете иметь дело с информацией, которую он вам дал.
Это именно то, что происходит, когда вы делаете запрос Ajax.
findItem(function(item) {
// Do something with item
});
doSomethingElse();
Вместо ожидания ответа выполнение продолжается немедленно и выполняется оператор после вызова Ajax. Чтобы в конечном итоге получить ответ, вы предоставляете функцию, которая будет вызываться после получения ответа, обратный вызов (заметьте что-нибудь, « перезвоните» ). Любой оператор, следующий за этим вызовом, выполняется до вызова обратного вызова.
Решение (s)
Примите асинхронную природу JavaScript! Хотя некоторые асинхронные операции предоставляют синхронные аналоги (как и «Ajax»), обычно их не рекомендуется использовать, особенно в контексте браузера.
Почему это плохо, спросите вы?
JavaScript запускается в потоке пользовательского интерфейса браузера, и любой длительный процесс блокирует пользовательский интерфейс, что делает его неотзывчивым. Кроме того, существует верхний предел времени выполнения для JavaScript, и браузер спросит пользователя, продолжать ли выполнение или нет.
Все это действительно плохой пользовательский опыт. Пользователь не сможет сказать, все ли работает нормально или нет. Кроме того, эффект будет хуже для пользователей с медленным соединением.
Далее мы рассмотрим три различных решения, которые все строятся друг на друге:
- Обещания с
async/await
(ES2017 +, доступный в старых браузерах, если вы используете транспортер или регенератор)
- Обратные вызовы (популярные в узле)
- Обещания с
then()
(ES2015 +, доступно в старых браузерах, если вы используете одну из множества библиотек обещаний)
Все три доступны в текущих браузерах, и узел 7+.
Версия ECMAScript, выпущенная в 2017 году, представила поддержку на уровне синтаксиса для асинхронных функций. С помощью async
и await
вы можете написать асинхронный в «синхронном стиле». Код все еще асинхронный, но его легче читать / понимать.
async/await
основывается на обещаниях: async
функция всегда возвращает обещание. await
«разворачивает» обещание и либо приводит к значению, с которым обещание было разрешено, либо выдает ошибку, если обещание было отклонено.
Важно: вы можете использовать только await
внутри async
функции. В настоящее время верхний уровень await
еще не поддерживается, поэтому вам может потребоваться сделать асинхронное IIFE ( выражение для немедленного вызова функции ), чтобы запустить async
контекст.
Вы можете прочитать больше о async
и await
на MDN.
Вот пример, который основан на задержке выше:
// Using 'superagent' which will return a promise.
var superagent = require('superagent')
// This is isn't declared as `async` because it already returns a promise
function delay() {
// `delay` returns a promise
return new Promise(function(resolve, reject) {
// Only `delay` is able to resolve or reject the promise
setTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
});
}
async function getAllBooks() {
try {
// GET a list of book IDs of the current user
var bookIDs = await superagent.get('/user/books');
// wait for 3 seconds (just for the sake of this example)
await delay();
// GET information about each book
return await superagent.get('/books/ids='+JSON.stringify(bookIDs));
} catch(error) {
// If any of the awaited promises was rejected, this catch block
// would catch the rejection reason
return null;
}
}
// Start an IIFE to use `await` at the top level
(async function(){
let books = await getAllBooks();
console.log(books);
})();
Поддержка текущих версий браузера и узлаasync/await
. Вы также можете поддерживать более старые среды, преобразовав свой код в ES5 с помощью регенератора (или инструментов, использующих регенератор, таких как Babel ).
Пусть функции принимают обратные вызовы
Обратный вызов - это просто функция, переданная другой функции. Эта другая функция может вызывать функцию, переданную всякий раз, когда она готова. В контексте асинхронного процесса обратный вызов будет вызываться всякий раз, когда выполняется асинхронный процесс. Обычно результат передается обратному вызову.
В примере с вопросом вы можете foo
принять обратный вызов и использовать его в качестве success
обратного вызова. Так это
var result = foo();
// Code that depends on 'result'
становится
foo(function(result) {
// Code that depends on 'result'
});
Здесь мы определили функцию «inline», но вы можете передать любую ссылку на функцию:
function myCallback(result) {
// Code that depends on 'result'
}
foo(myCallback);
foo
само определяется следующим образом:
function foo(callback) {
$.ajax({
// ...
success: callback
});
}
callback
будет ссылаться на функцию, которую мы передаем, foo
когда мы ее вызываем, и мы просто передаем ее success
. Т.е. как только Ajax-запрос будет успешным, $.ajax
он вызовет callback
и передаст ответ на обратный вызов (на который можно ссылаться result
, поскольку именно так мы определили обратный вызов).
Вы также можете обработать ответ, прежде чем передать его обратному вызову:
function foo(callback) {
$.ajax({
// ...
success: function(response) {
// For example, filter the response
callback(filtered_response);
}
});
}
Писать код с помощью обратных вызовов проще, чем может показаться. В конце концов, JavaScript в браузере сильно зависит от событий (события DOM). Получение ответа Ajax - не что иное, как событие.
Сложности могут возникнуть, когда вам придется работать со сторонним кодом, но большинство проблем можно решить, просто продумав поток приложения.
ES2015 +: обещания с then ()
Promise API является новой функцией ECMAScript 6 (ES2015), но она имеет хорошую поддержку браузера уже. Есть также много библиотек, которые реализуют стандартный API Promises и предоставляют дополнительные методы для упрощения использования и составления асинхронных функций (например, bluebird ).
Обещания - это контейнеры для будущих ценностей. Когда обещание получает значение (оно разрешено ) или когда оно отменено ( отклонено ), оно уведомляет всех своих «слушателей», которые хотят получить доступ к этому значению.
Преимущество по сравнению с простыми обратными вызовами состоит в том, что они позволяют вам отделить ваш код, и их легче составлять.
Вот простой пример использования обещания:
function delay() {
// `delay` returns a promise
return new Promise(function(resolve, reject) {
// Only `delay` is able to resolve or reject the promise
setTimeout(function() {
resolve(42); // After 3 seconds, resolve the promise with value 42
}, 3000);
});
}
delay()
.then(function(v) { // `delay` returns a promise
console.log(v); // Log the value once it is resolved
})
.catch(function(v) {
// Or do something else if it is rejected
// (it would not happen in this example, since `reject` is not called).
});
Применительно к нашему вызову Ajax мы можем использовать такие обещания:
function ajax(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
resolve(this.responseText);
};
xhr.onerror = reject;
xhr.open('GET', url);
xhr.send();
});
}
ajax("/echo/json")
.then(function(result) {
// Code depending on result
})
.catch(function() {
// An error occurred
});
Описание всех преимуществ, которые обещают предложить, выходит за рамки этого ответа, но если вы пишете новый код, вы должны серьезно рассмотреть их. Они обеспечивают отличную абстракцию и разделение вашего кода.
Больше информации об обещаниях: HTML5 - скалы - Обещания JavaScript
Примечание: отложенные объекты jQuery
Отложенные объекты - это пользовательская реализация обещаний в jQuery (до стандартизации API Promise). Они ведут себя почти как обещания, но выставляют немного другой API.
Каждый Ajax-метод jQuery уже возвращает «отложенный объект» (фактически обещание отложенного объекта), который вы можете просто вернуть из своей функции:
function ajax() {
return $.ajax(...);
}
ajax().done(function(result) {
// Code depending on result
}).fail(function() {
// An error occurred
});
Примечание: обещание получилось
Помните, что обещания и отложенные объекты - это просто контейнеры для будущей стоимости, а не сама стоимость. Например, предположим, у вас было следующее:
function checkPassword() {
return $.ajax({
url: '/password',
data: {
username: $('#username').val(),
password: $('#password').val()
},
type: 'POST',
dataType: 'json'
});
}
if (checkPassword()) {
// Tell the user they're logged in
}
Этот код неправильно понимает вышеуказанные проблемы асинхронности. В частности, $.ajax()
не останавливает код, пока проверяет страницу «/ пароль» на вашем сервере - он отправляет запрос на сервер и, ожидая, немедленно возвращает объект JQuery Ajax Deferred, а не ответ от сервера. Это означает, что if
оператор будет всегда получать этот отложенный объект, обрабатывать его как true
и продолжать, как если бы пользователь вошел в систему. Не хорошо.
Но исправить это легко:
checkPassword()
.done(function(r) {
if (r) {
// Tell the user they're logged in
} else {
// Tell the user their password was bad
}
})
.fail(function(x) {
// Tell the user something bad happened
});
Не рекомендуется: синхронные вызовы "Ajax"
Как я уже говорил, некоторые (!) Асинхронные операции имеют синхронные аналоги. Я не защищаю их использование, но для полноты картины, вот как вы должны выполнить синхронный вызов:
Без jQuery
Если вы напрямую используете XMLHTTPRequest
объект, передайте в false
качестве третьего аргумента .open
.
JQuery
Если вы используете jQuery , вы можете установить async
опцию на false
. Обратите внимание, что эта опция устарела начиная с jQuery 1.8. Затем вы можете использовать success
обратный вызов или получить доступ к responseText
свойству объекта jqXHR :
function foo() {
var jqXHR = $.ajax({
//...
async: false
});
return jqXHR.responseText;
}
Если вы используете любой другой метод jQuery Ajax, такой как $.get
, $.getJSON
и т. Д., Вы должны изменить его на $.ajax
(поскольку вы можете только передавать параметры конфигурации в $.ajax
).
Берегись! Невозможно сделать синхронный запрос JSONP . JSONP по своей природе всегда асинхронен (еще одна причина, чтобы даже не рассматривать эту опцию).
If you use any other jQuery AJAX method, such as $.get, $.getJSON, etc., you have them to $.ajax.
(Да, я понимаю, что мой ник в этом случае немного ироничен)foo
вызывается и передается функция (foo(function(result) {....});
)?result
используется внутри этой функции и является ответом на запрос Ajax. Чтобы обратиться к этой функции, первый параметр foo вызываетсяcallback
и назначаетсяsuccess
вместо анонимной функции. Итак,$.ajax
позвоним,callback
когда запрос был успешным. Я попытался объяснить это немного больше.$.getJSON
если хотите, чтобы запрос Ajax был синхронным. Однако вы не должны хотеть, чтобы запрос был синхронным, так что это не применяется. Вы должны использовать обратные вызовы или обещания для обработки ответа, как это объяснялось ранее в ответе.Если вы не используете JQuery в своем коде, этот ответ для вас
Ваш код должен быть примерно таким:
Феликс Клинг отлично справился с задачей, написав ответ для людей, использующих jQuery для AJAX. Я решил предоставить альтернативу тем, кто этого не делает.
( Обратите внимание, что для тех, кто использует новый
fetch
API, Angular или обещания, я добавил другой ответ ниже )С чем вы сталкиваетесь
Это краткое изложение «Объяснение проблемы» из другого ответа, если вы не уверены, прочитав это, прочитайте это.
В AJAX означает асинхронный . Это означает, что отправка запроса (или, вернее, получение ответа) исключается из обычного потока выполнения. В вашем примере сразу возвращается, и следующий оператор, выполняется до того, как функция, которую вы передали в качестве обратного вызова, даже была вызвана.
.send
return result;
success
Это означает, что при возврате определенный вами слушатель еще не выполнялся, а это означает, что возвращаемое вами значение не было определено.
Вот простая аналогия
(Fiddle)
Значение
a
возвращенное ,undefined
так какa=5
часть еще не выполнена. AJAX действует следующим образом: вы возвращаете значение до того, как у сервера появится возможность сообщить вашему браузеру, что это за значение.Одним из возможных решений этой проблемы является повторное активное программирование , сообщающее вашей программе, что делать после завершения расчета.
Это называется CPS . По сути, мы передаем
getFive
действие, которое нужно выполнить после его завершения, мы сообщаем нашему коду, как реагировать, когда событие завершается (например, наш вызов AJAX или в этом случае тайм-аут).Использование будет:
Который должен предупредить «5» на экране. (Fiddle) .
Возможные решения
Есть два основных способа решения этой проблемы:
1. Синхронный AJAX - не делай этого !!
Что касается синхронного AJAX, не делайте этого! Ответ Феликса вызывает некоторые убедительные аргументы о том, почему это плохая идея. Подводя итог, он замораживает браузер пользователя до тех пор, пока сервер не вернет ответ и не создаст очень плохой пользовательский опыт. Вот еще одно краткое изложение MDN о том, почему:
Если вам нужно сделать это, вы можете передать флаг: Вот как:
2. Код реструктуризации
Позвольте вашей функции принять обратный вызов. В приведенном примере код
foo
может быть сделан для принятия обратного вызова. Мы расскажем нашему коду, как реагировать послеfoo
завершения.Так:
становится:
Здесь мы передали анонимную функцию, но мы могли бы так же легко передать ссылку на существующую функцию, чтобы она выглядела так:
Для получения более подробной информации о том, как делается этот дизайн обратного вызова, проверьте ответ Феликса.
Теперь давайте определим сам foo, чтобы действовать соответственно
(Скрипка)
Теперь мы заставили нашу функцию foo принимать действие, которое будет выполняться после успешного завершения AJAX, мы можем расширить его, проверив, не является ли статус ответа 200 и действуя соответствующим образом (создайте обработчик ошибок и т. Д.). Эффективно решаем наш вопрос.
Если вам все еще трудно понять это, прочтите руководство по началу работы с AJAX на MDN.
источник
onload
обработчик, который срабатывает только когдаreadyState
есть4
. Конечно, это не поддерживается в IE8. (iirc, возможно, понадобится подтверждение.)XMLHttpRequest 2 (прежде всего прочитайте ответы Бенджамина Грюнбаума и Феликса Клинга )
Если вы не используете jQuery и хотите получить хороший короткий XMLHttpRequest 2, который работает в современных браузерах, а также в мобильных браузерах, я предлагаю использовать его следующим образом:
Как вы видете:
Есть два способа получить ответ на этот вызов Ajax (три с использованием имени переменной XMLHttpRequest):
Простейший:
Или, если по какой-то причине вы
bind()
перезвоните в класс:Пример:
Или (вышеприведенный лучше анонимные функции всегда проблема):
Нет ничего проще.
Теперь некоторые люди, вероятно, скажут, что лучше использовать onreadystatechange или даже имя переменной XMLHttpRequest. Это неверно.
Ознакомьтесь с расширенными функциями XMLHttpRequest
Поддерживаются все * современные браузеры. И я могу подтвердить, что я использую этот подход, так как существует XMLHttpRequest 2. У меня никогда не было никаких проблем во всех браузерах, которые я использую.
onreadystatechange полезен, только если вы хотите получить заголовки в состоянии 2.
Использование имени
XMLHttpRequest
переменной является еще одной большой ошибкой, так как вам необходимо выполнить обратный вызов внутри замыканий onload / oreadystatechange, иначе вы его потеряли.Теперь, если вы хотите что-то более сложное, используя post и FormData, вы можете легко расширить эту функцию:
Опять же ... это очень короткая функция, но она получает и публикует.
Примеры использования:
Или передайте полный элемент формы (
document.getElementsByTagName('form')[0]
):Или установите некоторые пользовательские значения:
Как видите, я не реализовал синхронизацию ... это плохо.
Сказав это ... почему бы не сделать это простым способом?
Как уже упоминалось в комментарии, использование error && синхронный полностью нарушает смысл ответа. Какой хороший короткий способ правильно использовать Ajax?
Обработчик ошибок
В приведенном выше сценарии у вас есть обработчик ошибок, который статически определен, поэтому он не ставит под угрозу функцию. Обработчик ошибок можно использовать и для других функций.
Но чтобы действительно вывести ошибку, единственный способ - написать неправильный URL, и в этом случае каждый браузер выдает ошибку.
Обработчики ошибок могут быть полезны, если вы устанавливаете пользовательские заголовки, устанавливаете responseType для буфера массива blob или чего-то еще ...
Даже если вы передадите POSTAPAPAP в качестве метода, он не выдаст ошибку.
Даже если вы передадите 'fdggdgilfdghfldj' в качестве форм-данных, это не выдаст ошибку.
В первом случае ошибка находится внутри
displayAjax()
подthis.statusText
asMethod not Allowed
.Во втором случае это просто работает. Вы должны проверить на стороне сервера, если вы передали правильные данные поста.
междоменный домен не разрешен, выдает ошибку автоматически.
В ответе об ошибке нет кодов ошибок.
Существует только то,
this.type
что установлено на ошибку.Зачем добавлять обработчик ошибок, если вы полностью не можете контролировать ошибки? Большинство ошибок возвращаются внутри этого в функции обратного вызова
displayAjax()
.Итак: нет необходимости в проверке ошибок, если вы можете правильно скопировать и вставить URL. ;)
PS: В качестве первого теста я написал x ('x', displayAjax) ..., и он полностью получил ответ ... ??? Поэтому я проверил папку, в которой находится HTML, и там был файл с именем «x.xml». Так что даже если вы забудете расширение вашего файла, XMLHttpRequest 2 НАЙДЕТ ЕГО . Я смеюсь
Чтение файла синхронно
Не делай этого.
Если вы хотите на время заблокировать браузер, загрузите красивый большой
.txt
файл синхронно.Теперь вы можете сделать
Нет другого способа сделать это не асинхронно. (Да, с циклом setTimeout ... но серьезно?)
Другой момент ... если вы работаете с API-интерфейсами, или просто с файлами собственного списка, или с чем угодно, вы всегда используете разные функции для каждого запроса ...
Только если у вас есть страница, на которую вы загружаете всегда один и тот же XML / JSON или что вам нужно, только одна функция. В этом случае немного измените функцию Ajax и замените b своей специальной функцией.
Функции выше для основного использования.
Если вы хотите расширить функцию ...
Да, ты можешь.
Я использую множество API, и одной из первых функций, которые я интегрирую в каждую HTML-страницу, является первая функция Ajax в этом ответе, только с GET ...
Но вы можете многое сделать с XMLHttpRequest 2:
Я сделал менеджер загрузок (используя диапазоны с обеих сторон с помощью резюме, файлового ридера, файловой системы), различные конвертеры, изменяющие размеры изображения, используя холст, заполнял базы данных веб-SQL с помощью base64images и многое другое ... Но в этих случаях вы должны создать функцию только для этого цель ... иногда вам нужны блоб, буферы массива, вы можете установить заголовки, переопределить mimetype и многое другое ...
Но вопрос здесь в том, как вернуть ответ Ajax ... (я добавил простой способ.)
источник
x
,ajax
илиxhr
может быть лучше :)). Я не вижу, как он обращается, возвращая ответ от вызова AJAX. (кто-то еще может сделатьvar res = x("url")
и не понять, почему это не работает;)). С другой стороны - было бы здорово, если бы вы вернулисьc
из метода, чтобы пользователи могли зацепитьсяerror
и т. Д.2.ajax is meant to be async.. so NO var res=x('url')..
Вот и весь смысл этого вопроса и ответов :)Если вы используете обещания, этот ответ для вас.
Это означает AngularJS, jQuery (с отсрочкой), замену (извлечение) нативного XHR, сохранение EmberJS, BackboneJS или любую библиотеку узлов, которая возвращает обещания.
Ваш код должен быть примерно таким:
Феликс Клинг отлично справился с написанием ответа для людей, использующих jQuery с обратными вызовами для AJAX. У меня есть ответ для родного XHR. Этот ответ предназначен для общего использования обещаний на веб-интерфейсе или на сервере.
Основная проблема
Модель параллелизма JavaScript в браузере и на сервере с NodeJS / io.js является асинхронной и реактивной .
Всякий раз, когда вы вызываете метод, который возвращает обещание,
then
обработчики всегда выполняются асинхронно, то есть после кода ниже них, которого нет в.then
обработчике.Это означает, что когда вы возвращаете
data
определенныйthen
вами обработчик, он еще не выполнялся. Это, в свою очередь, означает, что возвращаемое вами значение не было правильно установлено во времени.Вот простая аналогия для вопроса:
Значение
data
является ,undefined
так какdata = 5
часть еще не выполнена. Вероятно, он будет выполнен через секунду, но к тому времени он не будет иметь отношения к возвращаемому значению.Поскольку операция еще не произошла (AJAX, серверный вызов, IO, таймер), вы возвращаете значение до того, как запрос получит возможность сообщить вашему коду, что это за значение.
Одним из возможных решений этой проблемы является повторное активное программирование , сообщающее вашей программе, что делать после завершения расчета. Обещания активно способствуют этому, будучи временными (чувствительными ко времени) по своей природе.
Краткий обзор обещаний
Обещание - это ценность с течением времени . Обещания имеют состояние, они начинаются как ожидающие без значения и могут рассчитывать на:
Обещание может изменить состояние только один раз, после чего оно всегда будет оставаться в одном и том же состоянии навсегда. Вы можете прикрепить
then
обработчики к обещаниям, чтобы извлечь их значение и обработать ошибки.then
обработчики позволяют связывать вызовы. Обещания создаются с помощью API, которые их возвращают . Например, более современная замена AJAXfetch
или$.get
обещания возврата jQuery .Когда мы вызываем
.then
обещание и возвращаем что-то из него - мы получаем обещание для обработанного значения . Если мы ответим на другое обещание, мы получим удивительные вещи, но давайте держать наших лошадейС обещаниями
Давайте посмотрим, как мы можем решить вышеуказанную проблему с обещаниями. Во-первых, давайте продемонстрируем наше понимание состояний обещаний сверху, используя конструктор Promise для создания функции задержки:
Теперь, после того как мы преобразовали setTimeout для использования обещаний, мы можем использовать
then
его для подсчета:В принципе, вместо того , чтобы возвращать значение , которое мы не можем сделать из модели параллелизма - мы возвращаемся в обертку для значения , которое мы можем UnWrap с
then
. Это как коробка, с которой вы можете открытьthen
.Применяя это
То же самое относится к исходному вызову API, вы можете:
Так что это работает так же хорошо. Мы узнали, что не можем возвращать значения из уже асинхронных вызовов, но мы можем использовать обещания и объединять их в цепочку для выполнения обработки. Теперь мы знаем, как вернуть ответ от асинхронного вызова.
ES2015 (ES6)
ES6 представляет генераторы, которые являются функциями, которые могут возвращаться в середине и затем возвращаться к точке, в которой они находились. Это обычно полезно для последовательностей, например:
Функция, которая возвращает итератор последовательности,
1,2,3,3,3,3,....
которая может быть повторена. Хотя это само по себе интересно и открывает много возможностей, есть один интересный случай.Если последовательность, которую мы создаем, является последовательностью действий, а не чисел - мы можем приостановить функцию всякий раз, когда действие дается, и ждать его, прежде чем мы возобновим функцию. Таким образом, вместо последовательности чисел нам нужна последовательность будущих значений, то есть обещаний.
Этот несколько хитрый, но очень мощный трюк позволяет нам писать асинхронный код синхронно. Есть несколько «бегунов», которые делают это для вас, написание одного - несколько строк кода, но выходит за рамки этого ответа. Я буду использовать Bluebird
Promise.coroutine
здесь, но есть и другие обертки, такие какco
илиQ.async
.Этот метод возвращает само обещание, которое мы можем использовать из других сопрограмм. Например:
ES2016 (ES7)
В ES7 это еще более стандартизировано, сейчас есть несколько предложений, но во всех из них вы можете
await
пообещать. Это просто «сахар» (лучше синтаксис) для предложения ES6 выше, добавивasync
иawait
ключевые слова. Делаем приведенный выше пример:Это все еще возвращает обещание точно так же :)
источник
return await data.json();
?)Вы используете Ajax неправильно. Идея не в том, чтобы он что-либо возвращал, а в том, чтобы передать данные чему-то, что называется функцией обратного вызова, которая обрабатывает данные.
Это:
Возврат чего-либо в обработчик отправки ничего не сделает. Вместо этого вы должны либо передать данные, либо сделать то, что вы хотите, непосредственно внутри функции успеха.
источник
success: handleData
и это будет работать.success
метод, а окружающая область$.ajax
.Самое простое решение - создать функцию JavaScript и вызвать ее для
success
обратного вызова Ajax .источник
Я отвечу ужасно выглядящим, нарисованным от руки комиксом. Второе изображение является причиной , почему
result
этоundefined
в вашем примере кода.источник
Angular1
Для людей, которые используют AngularJS , могут справиться с этой ситуацией, используя
Promises
.Здесь говорится,
Вы также можете найти хорошее объяснение здесь .
Пример найден в документах, упомянутых ниже.
Angular2 и позже
В
Angular2
с видом на следующем примере, но его рекомендуется для использованияObservables
сAngular2
.}
Вы можете потреблять это таким образом,
Смотрите оригинальный пост здесь. Но Typescript не поддерживает встроенные обещания es6 , если вы хотите его использовать, вам может понадобиться плагин для этого.
Кроме того, здесь приведена спецификация обещаний .
источник
Большинство ответов здесь дают полезные советы, когда у вас есть одна асинхронная операция, но иногда это возникает, когда вам нужно выполнить асинхронную операцию для каждой записи в массиве или другой структуре, подобной списку. Соблазн сделать это:
Пример:
Показать фрагмент кода
Причина, по которой это не работает, заключается в том, что обратные вызовы из
doSomethingAsync
еще не запущены к тому времени, когда вы пытаетесь использовать результаты.Таким образом, если у вас есть массив (или какой-то список) и вы хотите выполнять асинхронные операции для каждой записи, у вас есть два варианта: выполнять операции параллельно (с наложением) или последовательно (одна за другой в последовательности).
Параллельно
Вы можете запустить их все и отследить, сколько обратных вызовов вы ожидаете, а затем использовать результаты, когда вы получили столько обратных вызовов:
Пример:
Показать фрагмент кода
(Мы могли бы покончить с этим
expecting
и просто использоватьresults.length === theArray.length
, но это оставляет нас открытыми для возможности, котораяtheArray
изменяется, пока звонки ожидают ...)Обратите внимание, как мы используем
index
fromforEach
для сохранения результата вresults
той же позиции, что и запись, к которой он относится, даже если результаты поступают не по порядку (поскольку асинхронные вызовы не обязательно завершаются в том порядке, в котором они были запущены).Но что, если вам нужно вернуть эти результаты из функции? Как указали другие ответы, вы не можете; вам нужно, чтобы ваша функция принимала и вызывала обратный вызов (или возвращала обещание ). Вот версия обратного вызова:
Пример:
Показать фрагмент кода
Или вот версия, возвращающая
Promise
вместо:Конечно, если
doSomethingAsync
мы передадим нам ошибки, мы бы использовалиreject
отклонение обещания, когда получили ошибку.)Пример:
Показать фрагмент кода
(Или, альтернативно, вы можете создать оболочку,
doSomethingAsync
которая возвращает обещание, а затем сделать следующее ...)Если
doSomethingAsync
дает вам обещание , вы можете использоватьPromise.all
:Если вы знаете, что
doSomethingAsync
будет игнорироваться второй и третий аргумент, вы можете просто передать его напрямуюmap
(map
вызывает его обратный вызов с тремя аргументами, но большинство людей используют только первый большую часть времени):Пример:
Показать фрагмент кода
Обратите внимание, что
Promise.all
это обещание разрешается с помощью массива результатов всех обещаний, которые вы даете ему, когда все они разрешены, или отклоняет свое обещание, когда первое из обещаний, которые вы даете, отклоняет его.Серии
Предположим, вы не хотите, чтобы операции были параллельными? Если вы хотите запускать их один за другим, вам нужно дождаться завершения каждой операции, прежде чем начинать следующую. Вот пример функции, которая делает это и вызывает обратный вызов с результатом:
(Поскольку мы выполняем эту работу последовательно, мы можем просто использовать ее,
results.push(result)
поскольку знаем, что не получим результаты не в порядке. В приведенном вышеresults[index] = result;
примере мы могли бы использовать , но в некоторых из следующих примеров у нас нет индекса использовать.)Пример:
Показать фрагмент кода
(Или, опять же, создайте обертку,
doSomethingAsync
которая даст вам обещание и сделайте следующее ...)Если
doSomethingAsync
вы получите Обещание, если вы можете использовать синтаксис ES2017 + (возможно, с помощью транспилятора, такого как Babel ), вы можете использоватьasync
функцию сfor-of
иawait
:Пример:
Показать фрагмент кода
Если вы не можете использовать синтаксис ES2017 + (пока), вы можете использовать вариант с шаблоном «Promise Reduce» (это более сложно, чем обычное сокращение Promise, потому что мы не передаем результат из одного в другое, а вместо этого собирая их результаты в массив):
Пример:
Показать фрагмент кода
... что менее сложно с функциями ES2015 + стрелка :
Пример:
Показать фрагмент кода
источник
if (--expecting === 0)
часть кода, пожалуйста? Версия обратного вызова вашего решения отлично работает для меня, я просто не понимаю, как с помощью этого заявления вы проверяете количество выполненных ответов. Ценю это просто отсутствие знаний с моей стороны. Есть ли альтернативный способ написания чека?expecting
начинается со значенияarray.length
, то есть сколько запросов мы собираемся сделать. Мы знаем, что обратный вызов не будет вызван, пока все эти запросы не будут запущены. В обратном вызовеif (--expecting === 0)
делает это: 1. Уменьшаетexpecting
(мы получили ответ, поэтому мы ожидаем на один ответ меньше), и если значение после уменьшения равно 0 (мы не ожидаем больше ответов), мы сделанный!results
не существовало). :-) Починил это.Посмотрите на этот пример:
Как вы видите
getJoke
, возвращение разрешенного обещания (оно разрешается при возвратеres.data.value
). Поэтому вы ждете, пока запрос $ http.get не будет выполнен, а затем будет выполнен console.log (res.joke) (как обычный асинхронный поток).Это плнкр:
http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/
ES6 способ (асинхронно - жду)
источник
Это одно из мест, где два способа привязки данных или концепция хранения, которые используются во многих новых JavaScript-фреймворках, будут отлично работать для вас ...
Так что, если вы используете Angular, React или любые другие фреймворки, которые используют два способа привязки данных или концепцию хранения, эта проблема просто решается для вас, так что, проще говоря, ваш результат находится
undefined
на первом этапе, поэтому вы получили егоresult = undefined
до того, как получите данные, а затем, как только вы получите результат, он будет обновлен и будет присвоен новое значение, ответ на ваш вызов Ajax ...Но как вы можете сделать это в чистом javascript или jQuery, например, как вы задали в этом вопросе?
Вы можете использовать обратный вызов , обещание и недавно наблюдаемый, чтобы обработать его для вас, например, в обещаниях у нас есть какая-то функция, подобная
success()
илиthen()
которая будет выполняться, когда ваши данные будут готовы для вас, то же самое с функцией обратного вызова или подписки для наблюдаемого .Например, в вашем случае, когда вы используете jQuery , вы можете сделать что-то вроде этого:
Для получения дополнительной информации изучите обещания и наблюдаемые, которые являются более новыми способами сделать это асинхронным материалом.
источник
$.ajax({url: "api/data", success: fooDone.bind(this)});
Это очень распространенная проблема, с которой мы сталкиваемся, борясь с «загадками» JavaScript. Позвольте мне попытаться раскрыть эту тайну сегодня.
Давайте начнем с простой функции JavaScript:
Это простой синхронный вызов функции (где каждая строка кода «заканчивается своей работой» перед следующей последовательной), и результат такой же, как и ожидалось.
Теперь давайте добавим небольшой поворот, введя небольшую задержку в нашу функцию, чтобы все строки кода не были «закончены» в последовательности. Таким образом, он будет эмулировать асинхронное поведение функции:
Итак, вы идете, эта задержка просто сломала функциональность, которую мы ожидали! Но что именно произошло? Ну, это на самом деле довольно логично, если вы посмотрите на код.
foo()
после выполнения функция ничего не возвращает (таким образом, возвращается значениеundefined
), но она запускает таймер, который выполняет функцию через 1 с, чтобы вернуть 'wohoo'. Но, как вы можете видеть, значение, назначенное для bar, является немедленно возвращаемым материалом из foo (), который является ничем, то есть простоundefined
.Итак, как нам решить эту проблему?
Давайте попросим нашу функцию для ОБЕЩАНИЯ . Обещание действительно о том, что оно означает: это означает, что функция гарантирует, что вы обеспечите любой вывод, который она получит в будущем. Итак, давайте посмотрим на это в действии для нашей маленькой проблемы выше:
Таким образом, сводка заключается в том, что - для решения асинхронных функций, таких как вызовы на основе ajax и т. Д., Вы можете использовать обещание для
resolve
значения (которое вы намереваетесь вернуть). Таким образом, короче говоря, вы разрешаете значение, а не возвращаете его в асинхронных функциях.ОБНОВЛЕНИЕ (обещания с асинхронным ожиданием)
Помимо использования
then/catch
для работы с обещаниями, существует еще один подход. Идея состоит в том, чтобы распознать асинхронную функцию и затем дождаться разрешения обещаний , прежде чем перейти к следующей строке кода. Это все еще толькоpromises
под капотом, но с другим синтаксическим подходом. Чтобы прояснить ситуацию, вы можете найти сравнение ниже:затем / поймать версию:
версия async / await:
источник
Другой подход для возврата значения из асинхронной функции - передать объект, который будет хранить результат от асинхронной функции.
Вот пример того же:
Я использую
result
объект для хранения значения во время асинхронной операции. Это позволяет результату быть доступным даже после асинхронного задания.Я часто использую этот подход. Мне было бы интересно узнать, насколько хорошо работает этот подход, когда речь идет о передаче результата через последовательные модули.
источник
result
. Это работает, потому что вы читаете переменную после завершения асинхронной функции.Несмотря на то, что обещания и обратные вызовы работают хорошо во многих ситуациях, в тылу трудно выразить что-то вроде:
Вы бы в конечном итоге пройти
async1
; проверьте,name
не определено ли или нет, и соответственно вызовите обратный вызов.Пока все нормально в небольших примерах это это раздражает, когда у вас много подобных случаев и обработка ошибок.
Fibers
помогает в решении проблемы.Вы можете оформить заказ здесь .
источник
async-await
если вы используете некоторые из новейших версий узла. Если кто-то застрял с более старыми версиями, он может использовать этот метод.В следующем примере, который я написал, показано, как
Этот рабочий пример самодостаточен. Он определит простой объект запроса, который использует
XMLHttpRequest
объект окна для выполнения вызовов. Он определит простую функцию, которая будет ждать выполнения обещаний.Контекст. Пример запрашивает конечную точку Spotify Web API для поиска
playlist
объектов для заданного набора строк запроса:Для каждого элемента новое Promise будет запускать блок -
ExecutionBlock
анализировать результат, планировать новый набор обещаний на основе массива результатов, который представляет собой списокuser
объектов Spotify, и выполнять новый HTTP-вызов вExecutionProfileBlock
асинхронном режиме.Затем вы можете увидеть вложенную структуру Promise, которая позволяет создавать множественные и полностью асинхронные вложенные HTTP-вызовы, а также объединять результаты каждого подмножества вызовов
Promise.all
.ПРИМЕЧАНИЕ. Для последних
search
API Spotify потребуется указать маркер доступа в заголовках запроса:Итак, чтобы запустить следующий пример, вам нужно поместить свой токен доступа в заголовки запроса:
Я подробно обсудил это решение здесь .
источник
Короткий ответ: вы должны реализовать обратный вызов, например:
источник
Ответ на 2017 год: теперь вы можете делать именно то, что вы хотите, в каждом текущем браузере и узле
Это довольно просто:
Вот рабочая версия вашего кода:
await поддерживается во всех текущих браузерах и узле 8
источник
await/async
Браузер можно разделить на три части:
1) Event Loop
2) Веб-API
3) Очередь событий
Цикл событий выполняется вечно, то есть, вид бесконечного цикла. Очередь событий - это место, где вся ваша функция помещается в какое-то событие (например, щелчок). Это выполняется одна за другой из очереди и помещается в цикл событий, который выполняет эту функцию и подготавливает ее самостоятельно. для следующего за первым выполняется. Это означает, что выполнение одной функции не начинается до тех пор, пока функция в очереди не будет выполнена в цикле обработки событий.
Теперь давайте подумаем, что мы поместили две функции в очередь: одна предназначена для получения данных с сервера, а другая использует эти данные. Сначала мы поместили функцию serverRequest () в очередь, а затем функцию utiliseData (). Функция serverRequest входит в цикл обработки событий и выполняет вызов к серверу, так как мы никогда не знаем, сколько времени потребуется для получения данных с сервера, поэтому ожидается, что этот процесс займет время, и поэтому мы заняты циклом обработки событий, таким образом, подвисая нашу страницу. API вступает в роль, он берет эту функцию из цикла событий и имеет дело с тем, что сервер делает цикл событий свободным, чтобы мы могли выполнить следующую функцию из очереди. Следующая функция в очереди - это utiliseData (), который идет в цикле, но из-за отсутствия доступных данных он идет растрата и выполнение следующей функции продолжается до конца очереди (это называется асинхронным вызовом, т.е. мы можем делать что-то еще, пока не получим данные)
Предположим, что у нашей функции serverRequest () есть код возврата в коде, когда мы получаем данные из серверного веб-API и помещаем их в очередь в конце очереди. Поскольку он помещается в конец очереди, мы не можем использовать его данные, так как в нашей очереди не осталось функции для использования этих данных. Таким образом, невозможно вернуть что-либо из Async Call.
Таким образом, решением этого является обратный вызов или обещание .
Изображение из одного из ответов здесь, Правильно объясняет использование обратного вызова ... Мы передаем нашу функцию (функцию, использующую данные, возвращенные с сервера) функции, вызывающей сервер.
В моем коде это называется
Javscript.info обратный вызов
источник
Вы можете использовать эту пользовательскую библиотеку (написанную с помощью Promise) для удаленного вызова.
Простой пример использования:
источник
Другое решение - выполнить код через последовательного исполнителя nsynjs .
Если основная функция обещана
nsynjs будет оценивать все обещания последовательно и помещать результат обещания в
data
свойство:Если основная функция не обещана
Шаг 1. Оберните функцию с обратным вызовом в оболочку с поддержкой nsynjs (если у нее обещанная версия, вы можете пропустить этот шаг):
Шаг 2. Ввести синхронную логику в функцию:
Шаг 3. Запустите функцию синхронно через nsynjs:
Nsynjs будет оценивать все операторы и выражения шаг за шагом, приостанавливая выполнение в случае, если результат какой-то медленной функции не готов.
Дополнительные примеры здесь: https://github.com/amaksr/nsynjs/tree/master/examples
источник
ECMAScript 6 имеет «генераторы», которые позволяют легко программировать в асинхронном стиле.
Для запуска приведенного выше кода вы делаете это:
Если вам нужно ориентироваться на браузеры, которые не поддерживают ES6, вы можете запустить код через Babel или closure-compiler для генерации ECMAScript 5.
Обратный вызов
...args
упакован в массив и деструктурирован, когда вы читаете их, чтобы шаблон мог справиться с обратными вызовами, которые имеют несколько аргументов. Например, с узлом fs :источник
Вот несколько подходов для работы с асинхронными запросами:
Пример: отложенная реализация jQuery для работы с несколькими запросами
источник
Мы попадаем во вселенную, которая, кажется, движется в измерении, которое мы называем «время». Мы не очень понимаем, что такое время, но мы разработали абстракции и словарный запас, которые позволяют нам рассуждать и говорить об этом: «прошлое», «настоящее», «будущее», «до», «после».
Компьютерные системы, которые мы создаем - все больше и больше - имеют время как важное измерение. Определенные вещи созданы, чтобы произойти в будущем. Тогда другие вещи должны произойти после того, как эти первые вещи в конечном итоге произойдут Это основное понятие называется «асинхронность». В нашем мире, который становится все более сетевым, наиболее распространенным случаем асинхронности является ожидание того, что удаленная система ответит на какой-либо запрос.
Рассмотрим пример. Вы звоните молочнику и заказываете молоко. Когда это приходит, вы хотите положить его в свой кофе. Вы не можете положить молоко в свой кофе прямо сейчас, потому что его еще нет. Вы должны ждать, пока оно придет, прежде чем положить его в свой кофе. Другими словами, следующее не будет работать:
Потому что JS не имеет возможности узнать , что нужно ждать для
order_milk
до конца перед выполнениемput_in_coffee
. Другими словами, он не знает, чтоorder_milk
является асинхронным - это то, что не приведет к молоку до некоторого будущего времени. JS и другие декларативные языки выполняют один оператор за другим без ожидания.Классический подход JS к этой проблеме, использующий преимущество того факта, что JS поддерживает функции как объекты первого класса, которые могут быть переданы, состоит в том, чтобы передать функцию в качестве параметра асинхронному запросу, который он затем вызовет после завершения. его задача когда-нибудь в будущем. Это подход "обратного вызова". Это выглядит так:
order_milk
начинает, приказывает молоко, затем, когда и только когда оно прибывает, оно вызываетput_in_coffee
.Проблема с этим подходом обратного вызова состоит в том, что он загрязняет нормальную семантику функции, сообщающей о своем результате
return
; вместо этого функции не должны сообщать о своих результатах, вызывая функцию обратного вызова, заданную в качестве параметра. Кроме того, этот подход может быстро стать громоздким при работе с более длинными последовательностями событий. Например, предположим, что я хочу подождать, пока молоко будет добавлено в кофе, а затем и только тогда выполнить третий шаг, а именно выпить кофе. В итоге мне нужно написать что-то вроде этого:где я передаю
put_in_coffee
и молоко, чтобы вставить его, и также действие (drink_coffee
), которое нужно выполнить после того, как молоко было введено. Такой код становится трудно писать, читать и отлаживать.В этом случае мы могли бы переписать код в вопросе как:
Введите обещания
Это послужило мотивацией для понятия «обещание», которое представляет собой особый тип значения, представляющий будущий или какой-то асинхронный результат. Это может представлять собой то, что уже произошло, или произойдет в будущем, или может вообще никогда не произойти. Обещания имеют единственный метод с именем
then
, которому вы передаете действие, которое будет выполнено, когда результат, который представляет обещание, будет реализован.В случае нашего молока и кофе мы
order_milk
планируем вернуть обещание на прибытие молока, а затем указатьput_in_coffee
в качествеthen
действия следующее:Одним из преимуществ этого является то, что мы можем связать их вместе, чтобы создать последовательности будущих вхождений («цепочка»):
Давайте применим обещания к вашей конкретной проблеме. Мы обернем нашу логику запроса внутри функции, которая возвращает обещание:
На самом деле, все, что мы сделали, это добавили
return
к вызову$.ajax
. Это работает, потому что jQuery$.ajax
уже возвращает что-то вроде обещания. (На практике, не вдаваясь в подробности, мы бы предпочли обернуть этот вызов так, чтобы он возвращал реальное обещание, или использовать какую-то альтернативу$.ajax
этому.) Теперь, если мы хотим загрузить файл и дождаться его завершения и затем сделать что-то, мы можем просто сказать,например,
При использовании обещаний мы в конечном итоге передаем множество функций
then
, поэтому часто полезно использовать более компактные функции стрелок в стиле ES6:async
ключевое словоНо все еще есть что-то смутно недовольное в том, что нужно писать код одним способом, если он синхронный, и совершенно другим способом, если он асинхронный. Для синхронного мы пишем
но если
a
асинхронный, с обещаниями мы должны написатьВыше мы говорили: «JS не может знать, что ему нужно дождаться завершения первого вызова, прежде чем он выполнит второй». Разве не было бы хорошо, если бы был какой-то способ сказать JS об этом? Оказывается, есть
await
ключевое слово, используемое внутри специального типа функции, называемой «асинхронная» функция. Эта функция является частью будущей версии ES, но она уже доступна в таких транспортерах, как Babel, с правильными настройками. Это позволяет нам просто написатьВ вашем случае вы сможете написать что-то вроде
источник
Краткий ответ : Ваш
foo()
метод возвращается немедленно, в то время как$ajax()
вызов выполняется асинхронно после завершения функции . Тогда проблема заключается в том, как или где хранить результаты, полученные асинхронным вызовом после его возврата.В этой теме было дано несколько решений. Возможно, самый простой способ - передать объект
foo()
методу и сохранить результаты в элементе этого объекта после завершения асинхронного вызова.Обратите внимание, что вызов по-
foo()
прежнему не вернет ничего полезного. Однако результат асинхронного вызова теперь будет храниться вresult.response
.источник
Используйте
callback()
функцию внутриfoo()
успеха. Попробуй таким образом. Это просто и легко понять.источник
Вопрос был:
что МОЖЕТ быть интерпретировано как:
Решение будет заключаться в том, чтобы избежать обратных вызовов и использовать комбинацию Promises и async / await .
Я хотел бы привести пример запроса Ajax.
(Хотя он может быть написан на Javascript, я предпочитаю писать его на Python и компилировать в Javascript с использованием Transcrypt . Это будет достаточно ясно.)
Давайте сначала включим использование JQuery, чтобы оно было
$
доступно какS
:Определите функцию, которая возвращает Promise , в данном случае Ajax-вызов:
Используйте асинхронный код, как если бы он был синхронным :
источник
Используя Promise
Наиболее совершенным ответом на этот вопрос является использование
Promise
.Применение
Но ждать...!
Существует проблема с использованием обещаний!
Почему мы должны использовать наши собственные обещания?
Я использовал это решение некоторое время, пока не выяснил, есть ли ошибка в старых браузерах:
Поэтому я решил реализовать свой собственный класс Promise для ES3 для компиляторов ниже js, если он не определен. Просто добавьте этот код перед вашим основным кодом, а затем смело используйте Promise!
источник
Конечно, есть много подходов, таких как синхронный запрос, обещание, но из моего опыта я думаю, что вы должны использовать подход обратного вызова. Это естественно для асинхронного поведения Javascript. Итак, ваш фрагмент кода может быть переписан немного иначе:
источник
Вместо того, чтобы бросать на вас код, есть две концепции, которые являются ключевыми для понимания того, как JS обрабатывает обратные вызовы и асинхронность. (Это вообще слово?)
Цикл событий и модель параллелизма
Есть три вещи, о которых вам нужно знать; Очередь; цикл событий и стек
В общих чертах, цикл событий похож на менеджера проектов, он постоянно прослушивает любые функции, которые хотят запустить, и обменивается данными между очередью и стеком.
Как только он получает сообщение для запуска чего-либо, он добавляет его в очередь. Очередь - это список вещей, которые ожидают выполнения (например, ваш AJAX-запрос). представьте это так:
Когда одно из этих сообщений будет выполнено, оно извлекает сообщение из очереди и создает стек, а стек - это все, что JS должен выполнить для выполнения инструкции в сообщении. Так что в нашем примере говорят
foobarFunc
Поэтому все, что нужно выполнить foobarFunc (в нашем случае
anotherFunction
), будет помещено в стек. выполнено, а затем забыто - цикл событий переместится на следующую вещь в очереди (или прослушает сообщения)Ключевым моментом здесь является порядок исполнения. Это
КОГДА-то собирается бежать
Когда вы делаете вызов с использованием AJAX внешней стороне или запускаете любой асинхронный код (например, setTimeout), Javascript зависит от ответа, прежде чем он сможет продолжить.
Большой вопрос, когда он получит ответ? Ответ - мы не знаем - поэтому цикл обработки событий ожидает, пока это сообщение не скажет «эй, беги меня». Если JS только что ждал этого сообщения синхронно, ваше приложение зависло бы, и оно было бы отстойным. Таким образом, JS продолжает выполнение следующего элемента в очереди, ожидая, когда сообщение будет добавлено в очередь.
Вот почему с асинхронной функциональностью мы используем вещи, называемые обратными вызовами . Это как обещание в буквальном смысле. Как и в обещание вернуть что-то в какой-то момент, jQuery использует специальные обратные вызовы, называемые
deffered.done
deffered.fail
иdeffered.always
(среди других). Вы можете увидеть их все здесьИтак, вам нужно передать функцию, которую обещают выполнить в какой-то момент, с данными, которые ему передают.
Поскольку обратный вызов не выполняется сразу, но в более позднее время важно передать ссылку на функцию, а не на ее выполнение. так
поэтому большую часть времени (но не всегда) , вы будете проходить
foo
неfoo()
Надеюсь, в этом есть смысл. Когда вы сталкиваетесь с такими вещами, которые кажутся запутанными, я настоятельно рекомендую прочитать документацию полностью, чтобы хотя бы понять ее. Это сделает вас намного лучшим разработчиком.
источник
Используя ES2017, вы должны иметь это как объявление функции
И выполнить это так.
Или синтаксис обещания
источник