Если вы начали свою карьеру разработчика около десяти лет назад, вы, вероятно, знаете, как сложно было использовать AJAX в наших веб-приложениях. Однако сейчас мы все знаем, что современный ванильный JavaScript предоставляет нам несколько мощных функциональных возможностей, включая Fetch API — более простой способ получения данных с сервера без перезагрузки страницы.
Термин AJAX (Asynchronous JavaScript and XML) появился в конце 1990-х годов как концепция программирования, которая позволяла обновлять части HTML DOM без полного обновления страницы, делая наши проекты более динамичными и интерактивными. Это стало возможным благодаря API XMLHttpRequest (появился в Internet Explorer 5 в 1998 году). Как следует из названия, этот API был разработан для получения XML через HTTP — а некоторое время спустя в него добавили поддержку других форматов, таких как JSON, HTML и обычный текст. Но работа с XMLHttpRequest в те времена была мучением, и поэтому некоторые библиотеки, такие как jQuery (созданная в 2006 году), абстрагировали его, чтобы облегчить использование.
Следуя эволюции JS, в 2015 году был представлен Fetch API, который сегодня стал стандартом для обработки запросов данных. До февраля этого года Fetch API работал только на стороне браузера, но теперь он работает и на стороне Node.js — но это всего лишь эксперимент, пока что нам нужно использовать такие библиотеки, как Axios API, чтобы лучше работать с запросами данных в Node.js.
Важные концепции JS: async, функции обратного вызова, обещание
Прежде чем перейти к Fetch API, давайте разберемся в некоторых концепциях JavaScript (для полного объяснения смотрите ссылки в конце статьи):
Что такое async в JavaScript?
По умолчанию JavaScript работает синхронно, как однопоточный язык программирования, что означает, что один процесс должен завершиться до начала другого. Однако есть несколько способов обеспечить одновременную работу процессов в JS, сделав наш код асинхронным.
Для простоты понимания представим, что вы идете в пиццерию, чтобы заказать пиццу. Обслуживающий персонал принимает ваш заказ и доставляет его на кухню. Синхронно, обслуживающий персонал должен подождать, пока ваша пицца будет приготовлена, принести ее вам, а затем пойти к другому клиенту, чтобы принять другой заказ, подождать, пока его пицца будет готова, и так далее. Как видите, это не самый лучший подход. С другой стороны, при асинхронном подходе обслуживающему персоналу не нужно ждать, пока пицца будет готова, чтобы перейти к следующему клиенту, он просто переходит к другому клиенту, принимая новые заказы и передавая их на кухню по мере готовности пиццы к доставке клиентам. В этом и заключается разница между синхронной и асинхронной системами.
Функции обратного вызова
Одним из самых старых и распространенных способов работы с асинхронным кодом в JS является использование функций обратного вызова. Это концепция JS, согласно которой функция: «жди выполнения в будущем, а не сейчас».
Функция обратного вызова — это функция, передаваемая в другую функцию в качестве аргумента, которая затем вызывается внутри внешней функции для завершения какого-либо действия. -MDN
Есть много способов реализовать это, например, когда нам нужно получить какие-то внешние данные и подождать ответа сервера, а затем сделать что-то другое. Именно здесь в игру вступает AJAX, и jQuery упрощает эту задачу, используя метод $.ajax()
своей библиотеки.
Но проблема с обратными вызовами начинается тогда, когда нам нужно вложить их для выполнения различных процессов — это называется адом обратных вызовов — что делает наш код очень сложным для чтения и сопровождения.
Promise в JS
В ES2015 появился Promise, современная альтернатива, позволяющая избежать ада обратных вызовов.
«Объект Promise представляет возможное завершение (или неудачу) асинхронной операции и ее результирующее значение.» -MDN
В двух словах, обещание действует как прокси для неизвестного значения, которое в конечном итоге станет доступным в какой-то момент, в конечном итоге как разрешенное состояние, если все идет хорошо, или как отклоненное состояние, если что-то идет не так.
Используя Promise, мы вызываем .then()
для выполнения, если результат разрешен, или .catch()
, если он отклонен. Кроме того, мы можем создавать цепочки обещаний, заставляя одно обещание возвращать другое обещание. Взгляните на пример ниже:
let myPromise = new Promise(function(myResolve, myReject) {
// "Producing Code" (May take some time)
myResolve(); // when successful
myReject(); // when error
});
// "Consuming Code" (Must wait for a fulfilled Promise)
myPromise.then(
function(value) {
/* code if successful */
},
function(error) {
/* code if some error */
}
);
Приведенный выше пример взят из W3Schools.
Что такое Fetch API в JavaScript и как его использовать?
Прежде чем рассказать о Fetch API, я хочу показать вам его синтаксис:
fetch('/https://api.github.com/users/diogorodrigues');
Приведенный выше код просто сделает HTTP-запрос к домену GitHub API, чтобы получить некоторые данные в формате JSON. Какой замечательный и лаконичный код, не правда ли!
Также в ES2015 появился Fetch API как современный преемник XMLHttpRequest
. Метод fetch()
принимает на вход путь к ресурсу и возвращает Promise, позволяя выполнить функцию в случае разрешения или отклонения.
fetch('https://api.github.com/users/diogorodrigues')
.then(response => response.json())
.then(data => console.log(data))
.catch(err => console.log(err));
В примере выше вы можете видеть метод fetch()
, работающий вместе с .then()
и .catch()
, поскольку Fetch API использует Promise за кулисами:
- Выполните HTTP-запрос к домену API GitHub.
- Если запрос разрешен, преобразуйте его в данные JSON с помощью метода
.json()
. - Поскольку метод
.json()
возвращает другой Promise, если он разрешен, отобразите результат в консоли. - В случае неудачи любого из описанных выше шагов выведите ошибку в консоль.
Async/Await и Fetch API
Async/Await был представлен в ES2017 и работает как синтаксический сахар для обещаний, позволяя работать с асинхронными функциями.
Смотрите код и его описание ниже, чтобы лучше понять, как реализовать Async/Await с помощью Fetch API:
async function getUserData() {
try {
const response = await fetch('https://api.github.com/users/diogorodrigues');
const data = await response.json();
console.log(data);
} catch (err) {
console.log(err);
}
}
Приведенный выше код работает так же, как и предыдущий. Разница в том, что нам больше не нужно использовать синтаксис обещания, вместо него мы используем обертку, чтобы переделать обещание, делая его более легким для чтения и использования. Мы используем ключевое слово async
, чтобы сделать эту функцию асинхронной, и await
, чтобы заблокировать выполнение кода внутри асинхронной функции до завершения процесса. Затем мы используем try/catch
для обработки разрешенного и отклоненного статуса.
Другой способ использования try/catch с асинхронными функциями — это обработка catch
вне функции — во время ее выполнения:
async function getUserData() {
const response = await fetch('https://api.github.com/users/diogorodrigues')
const data = await response.json()
console.log(data)
}
getUserData.catch(err => console.log(err))
Ссылки
- AJAX в Википедии
- API XMLHttpRequest на MDN
- Асинхронное программирование на JavaScript и обратные вызовы на Node.js
- Обратные вызовы на MDN
- Обещания на MDN
- Понимание обещаний JavaScript на Node.js
- Fetch на JavaScript.Info
- Async/await на JavaScript.Info
Заключение
В первые дни существования Интернета концепция AJAX активно использовалась вместе с API XMLHttpRequest. Сегодня у нас есть лучший и современный способ асинхронной обработки данных с помощью Fetch API. Надеюсь, вы поняли некоторые важные концепции JavaScript и то, как реализовать fetch()
в этой статье. Не стесняйтесь задавать вопросы и не останавливайтесь на достигнутом, посмотрите ссылки выше для лучшего понимания.
Увидимся в следующий раз. 😁
Пожертвование
Если вы нашли эту статью полезной, и вы хотите поддержать меня, чтобы я создавал больше подобного контента, вы можете купить мне кофе, нажав здесь. 😁
Очень благодарен.