Skip to content

Глава 4.5: Async/await vs Promise

Время изучения: 30 минут


1. Асинхронность: Два способа управления "космической связью"

Представьте, что ЦУП отправляет команду на Марс. Ответ придет только через несколько минут. Как организовать работу в это время?

Способ 1: "Протокол обратного вызова" (Promise с .then()) Вы отправляете команду и даете инструкцию: "КОГДА придет ответ, ТОГДА выполни вот эту функцию". Это похоже на цепочку событий.

Способ 2: "Режим ожидания" (Async/await) Вы говорите: "Я ПОДОЖДУ ответа на эту команду, но не буду блокировать другие пульты управления". Вы как бы ставите выполнение этой конкретной задачи на паузу, позволяя остальному ЦУПу работать.

Оба способа решают одну и ту же задачу — управление асинхронными операциями. async/await — это просто более современный и читаемый синтаксис, который работает "поверх" промисов.

💡 Космическая аналогия:

  • Promise с .then(): Это как написать на стикере: "Когда марсоход пришлет фото, передать его в отдел анализа".
  • Async/await: Это как сказать ассистенту: "Подожди фото от марсохода, а я пока займусь расчетами для запуска новой ракеты".

2. Promise с .then(): Классическая цепочка команд

Это фундаментальный способ работы с асинхронностью в JavaScript, который мы использовали в главе 4.1.

Вспомним наш первый код:

function getIssPositionWithPromises() {
    console.log('Отправляю запрос по протоколу "Promise"...');

    fetch('http://api.open-notify.org/iss-now.json')
        .then(response => {
            // Этап 1: Получен ответ
            if (!response.ok) {
                throw new Error(`Ошибка HTTP: ${response.status}`);
            }
            return response.json(); // Возвращаем новый промис
        })
        .then(data => {
            // Этап 2: Данные распарсены
            console.log('Данные по протоколу "Promise" получены:', data.iss_position);
        })
        .catch(error => {
            // Этап 3 (Ошибка): Что-то пошло не так на любом из этапов
            console.error('Сбой связи по протоколу "Promise":', error);
        });

    console.log('...команда отправлена, ЦУП продолжает работу...');
}

Плюсы:

  • Явная цепочка действий.
  • Хорошо подходит для простых последовательных операций.

Минусы:

  • "Ад обратных вызовов" (Callback Hell): При большом количестве вложенных асинхронных операций код может превратиться в "лесенку" из .then(), которую сложно читать.
  • Обработка ошибок может быть менее интуитивной.

3. Async/await: Современный синхронный стиль

async/await — это "синтаксический сахар" над промисами, который позволяет писать асинхронный код так, будто он синхронный.

Правила использования:

  1. Ключевое слово await можно использовать только внутри функции, помеченной как async.
  2. await ставится перед вызовом, который возвращает промис (например, fetch() или response.json()).
  3. await "приостанавливает" выполнение async-функции до тех пор, пока промис не будет разрешен, и возвращает его результат.

Тот же код, переписанный с async/await:

async function getIssPositionWithAsyncAwait() {
    console.log('Отправляю запрос по протоколу "Async/await"...');

    try {
        // Этап 1: Ждем ответ от сервера
        const response = await fetch('http://api.open-notify.org/iss-now.json');

        if (!response.ok) {
            throw new Error(`Ошибка HTTP: ${response.status}`);
        }

        // Этап 2: Ждем, пока тело ответа будет преобразовано в JSON
        const data = await response.json();

        console.log('Данные по протоколу "Async/await" получены:', data.iss_position);
    } catch (error) {
        // Этап 3 (Ошибка): Ловим любую ошибку из блока try
        console.error('Сбой связи по протоколу "Async/await":', error);
    }

    console.log('...команда отправлена, ЦУП продолжает работу...');
}

Плюсы:

  • Читаемость: Код выглядит почти как обычный синхронный код, его легко читать сверху вниз.
  • Обработка ошибок: Используется стандартный и привычный блок try...catch.
  • Отладка: Гораздо проще отлаживать, так как можно ставить точки останова (breakpoints) на каждой строке с await.

Минусы:

  • Легко забыть await или async, что приведет к ошибкам.

4. Когда какой протокол использовать?

Ситуация Рекомендуемый подход Почему?
Большинство случаев async/await Код чище, проще читать и отлаживать. Это современный стандарт.
Простая цепочка из 1-2 действий Promise с .then() Вполне подходит, код остается компактным.
Параллельное выполнение нескольких запросов Promise.all() Этот метод позволяет запустить несколько промисов одновременно и дождаться, пока все они выполнятся. async/await отлично с ним сочетается.

Пример с Promise.all():

async function getParallelData() {
    try {
        // Запускаем оба запроса одновременно
        const [shipsResponse, launchesResponse] = await Promise.all([
            fetch('https://api.spacexdata.com/v4/rockets'),
            fetch('https://api.spacexdata.com/v4/launches/latest')
        ]);

        if (!shipsResponse.ok || !launchesResponse.ok) {
            throw new Error('Один из запросов провалился!');
        }

        const rockets = await shipsResponse.json();
        const latestLaunch = await launchesResponse.json();

        console.log(`Всего ракет в флоте: ${rockets.length}`);
        console.log(`Последний запуск: ${latestLaunch.name}`);
    } catch (error) {
        console.error('Ошибка при получении параллельных данных:', error);
    }
}


Квиз для закрепления

1. `async/await` — это...

2. Какое ключевое слово обязательно для функции, внутри которой используется `await`?

3. Главное преимущество `async/await` перед `.then()`:

4. Что произойдет, если забыть `await` перед `fetch()` внутри `async`-функции?

5. `Promise.all()` используется для:


🚀 Итог главы:

Вы изучили два синтаксиса для управления асинхронными операциями и поняли, почему async/await является предпочтительным в большинстве современных проектов.

  • 🔗 Вы освежили знания о Promise с .then().
  • 🛠️ Вы глубоко поняли, как работает async/await и его преимущества.
  • ⚡ Вы узнали о Promise.all для выполнения параллельных запросов.

Протоколы связи изучены! В финальной главе этого раздела мы соберем все наши знания воедино и достроим наш "Центр Управления Полетами", создав полноценный интерфейс для всех CRUD-операций.

📌 Практика:

  • Перепишите все функции в вашем app.js, которые еще используют .then(), на синтаксис async/await.
  • Попробуйте добавить еще один запрос в Promise.all() (например, к https://api.spacexdata.com/v4/starlink) и вывести данные.

⚠️ Если ошибки:

  • await is only valid in async functions: Убедитесь, что функция, где вы используете await, помечена как async.
  • Переменная содержит [object Promise]: Вы забыли поставить await перед функцией, возвращающей промис.