Добро пожаловать на SO и спасибо за ваш вопрос. Я сделаю все возможное, чтобы показать вам несколько примеров того, как вы могли бы выполнить свой код таким образом, который может оказаться предпочтительным для вас в качестве решения.
Обратные вызовы
Что такое обратный вызов?
Проще говоря: обратный вызов - это функция, которая должна выполняться после завершения выполнения другой функции - отсюда и название «обратный вызов».
Источникquote
В вашем примере кода вы хотите выполнить как минимум 2 HTTP-запроса друг за другом. Это будет означать, что часть кода должна быть выполнена дважды. Для этого вы можете написать функцию вокруг элемента XMLHTTPRequest
, чтобы иметь возможность выполнять ее несколько раз, когда записываете ее только один раз.
Функция ниже имеет два параметра: url
и callback
. Параметр url
- это строка, которая будет вставлена во второй параметр метода xhr.open
. Параметр callback
будет функцией. Эта функция будет вызвана, когда запрос будет успешно завершен.
function get(url, callback) {
var xhr = new XMLHTTPRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
if ('function' === typeof callback) {
callback(xhr.responseText);
}
}
};
xhr.open('GET', url, true)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send();
}
Вот небольшой пример того, как это будет работать. Обратите внимание, что функция обратного вызова имеет параметр с именем data1
. Это xhr.responseText
, которое мы получили от XMLHTTPRequest
. Внутри функции обратного вызова снова вызовите функцию get
, чтобы сделать еще один запрос.
get('/ajax1.php', function(data1) {
// Do something with data1.
get('/ajax2.php', function(data2) {
// Do something with data2.
});
});
Это довольно простой способ сделать запрос после завершения другого.
Но что, если у нас будет 100 запросов друг за другом?
Обещанный XMLHTTPRequest
Объект Promise представляет возможное завершение (или сбой) асинхронной операции и ее итоговое значение.
Источник цитаты
Введите обещания. Пример ниже здесь почти такой же, как пример выше. Только на этот раз мы используем Promise
. При звонке get
мы сразу же возвращаем Promise
. Это обещание будет ждать себя либо resolve
, либо reject
. В этом случае мы используем resolve
только для успешных запросов. Когда запрос завершается, вызывается resolve
и начинается цепочка Promise .
function get(url) {
return new Promise(resolve => {
var xhr = new XMLHTTPRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
if ('function' === typeof callback) {
resolve(xhr.responseText);
}
}
};
xhr.open('GET', url, true)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send();
});
}
Поэтому вместо использования функции обратного вызова мы используем then
. Внутри then
мы используем функцию обратного вызова , которая позволяет нам использовать значение, которое было разрешено в возвращенном Promise
. then
можно объединять в цепочку с большим количеством then
, пока не закончится цепочка вещей.
Внутри функции обратного вызова вызовите следующий запрос.
get('/ajax1.php')
.then(data1 => {
// Do something with data1.
get('/ajax2.php')
.then(data2 => {
// Do something with data2.
});
});
Fetch
Fetch API предоставляет интерфейс для извлечения ресурсов (в том числе по сети). Это покажется знакомым всем, кто использовал XMLHttpRequest, но новый API предоставляет более мощный и гибкий набор функций.
Источник цитаты
Прежде чем мыМы создали нашу собственную Promise
версию XMLHTTPRequest. Но JavaScript развился и получил новые инструменты для работы. fetch
похоже на то, как работает наша get
функция, но имеет гораздо больше возможностей и опций, чтобы сделать ее более мощнойИ он также использует обещаний !
fetch('/ajax1.php')
.then(response1 => response1.text())
.then(data1 => {
// Do something with data1.
fetch('/ajax2.php')
.then(response2 => response2.text())
.then(data2 => {
// Do something with data2.
});
})
.catch(error => console.log(error));
Хотя синтаксис then
все еще заставляет нас вкладывать функции. Как и раньше, как быть, когда у вас есть 100 функций обратного вызова для вызова? Это будет беспорядок вложений!
Fetch + Async / Await
Теперь это способ решения проблемы вложенности и делает синтаксис более похожим на присвоение простой переменнойв JS. Async / Await является частью современного JavaScript, так что будьте осторожны со старыми браузерами, которые его не поддерживают. Проверьте caniuse на текущую поддержку.
Синтаксис Async / Await работает следующим образом. Создайте функцию с ключевым словом async
перед ней. Это будет указывать, как это подразумевает, что здесь будет выполняться асинхронный код. Он также выполняет функцию с асинхронной синхронизацией, прежде чем автоматически вернет Promise
.
Внутри асинхронной функции используйте ключевое слово await
всякий раз, когда вы вызываете функцию, которая возвращает Promise
, например fetch
, или нашу собственную функцию get
. Это вернет значение resolved без необходимости использования then
или функции обратного вызова.
Ключевое слово await
также делает код фактически wait , прежде чем продолжитьследующая строка кода. Теперь ваш JS выглядит хорошо и может быть написан с меньшим количеством вложений.
(async function() {
const response1 = await fetch('/ajax1.php');
const data1 = await response1.text();
// Do something with data1.
const response2 = await fetch('/ajax2.php');
const data2 = await response2.text();
// Do something with data1.
}());
Я действительно надеюсь, что это полезно и поможет вам добраться туда, куда вам нужно идти. Если у вас есть какие-либо вопросы относительно вышеизложенного, пожалуйста, дайте мне знать!
Имейте хороший!