PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Async/await в JavaScript: полное руководство 2024

    Async/await в JavaScript: полное руководство 2024

    Аватар автора Async/await в JavaScript: полное руководство 2024

    Антон Ларичев

    Иконка календаря28 июня 2026
    javascriptasyncawaitpromisesасинхронностьmiddleИконка уровня middle
    Картинка поста Async/await в JavaScript: полное руководство 2024

    Введение

    Асинхронное программирование — один из ключевых навыков JavaScript-разработчика. Долгое время для работы с асинхронным кодом использовались колбэки и промисы, но с появлением async/await в ES2017 код стал значительно чище и понятнее. В этом руководстве разберём всё: от внутреннего устройства до типичных ошибок на практике.

    Почему асинхронность важна

    JavaScript — однопоточный язык. Это означает, что все операции выполняются последовательно в одном потоке. Если заблокировать поток долгим запросом к серверу, интерфейс зависнет и пользователь ничего не сможет сделать.

    Асинхронный код позволяет запускать долгие операции (сетевые запросы, чтение файлов, таймеры) без блокировки основного потока. Пока операция выполняется «в фоне», поток свободен для другой работы.

    Event Loop и очередь задач

    Под капотом async/await работает Event Loop. Когда встречается await, выполнение функции приостанавливается, а управление возвращается вызывающему коду. Когда промис завершается, функция возобновляется с того места, где была остановлена.

    Промисы как основа async/await

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

    Промис — объект, представляющий результат асинхронной операции. Он может находиться в трёх состояниях: pending (ожидание), fulfilled (выполнен успешно), rejected (отклонён с ошибкой).

    // Создание промиса вручную
    const fetchUser = (id) => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (id > 0) {
            // Успешно возвращаем пользователя
            resolve({ id, name: 'Иван Петров' });
          } else {
            // Отклоняем с ошибкой при некорректном id
            reject(new Error('Некорректный ID пользователя'));
          }
        }, 1000);
      });
    };
    

    Синтаксис async/await

    Объявление async-функции

    Ключевое слово async перед функцией делает её асинхронной. Такая функция всегда возвращает промис, даже если внутри возвращается обычное значение.

    // Обычная async-функция
    async function getUser(id) {
      return { id, name: 'Иван' };
    }
    
    // Стрелочная async-функция
    const getProduct = async (id) => {
      return { id, price: 1500 };
    };
    
    // Оба варианта возвращают промис
    getUser(1).then(user => console.log(user)); // { id: 1, name: 'Иван' }
    

    Оператор await

    await можно использовать только внутри async-функции. Он приостанавливает выполнение до тех пор, пока промис не завершится, и возвращает его результат.

    async function loadUserProfile(userId) {
      // Ожидаем получения пользователя
      const user = await fetchUser(userId);
      
      // Ожидаем получения постов пользователя
      const posts = await fetchPosts(user.id);
      
      // Ожидаем получения комментариев к постам
      const comments = await fetchComments(posts[0].id);
      
      return { user, posts, comments };
    }
    

    Обработка ошибок

    try/catch с async/await

    Ошибки в async/await обрабатываются через стандартный try/catch, что делает код более читаемым по сравнению с цепочками .catch().

    async function loadData(userId) {
      try {
        const user = await fetchUser(userId);
        const posts = await fetchPosts(user.id);
        return { user, posts };
      } catch (error) {
        // Обрабатываем любую ошибку из цепочки await
        console.error('Ошибка загрузки данных:', error.message);
        throw error; // Пробрасываем ошибку выше при необходимости
      } finally {
        // Выполняется всегда — удобно для очистки ресурсов
        console.log('Загрузка завершена');
      }
    }
    

    Обработка ошибок для каждого await

    Иногда нужно обрабатывать ошибки для каждой операции отдельно:

    async function robustLoad(userId) {
      // Используем .catch() прямо на промисе для локальной обработки
      const user = await fetchUser(userId).catch(() => null);
      
      if (!user) {
        return { error: 'Пользователь не найден' };
      }
      
      const posts = await fetchPosts(user.id).catch(() => []);
      
      return { user, posts };
    }
    

    Параллельное выполнение

    Одна из частых ошибок — последовательное выполнение независимых запросов. Если запросы не зависят друг от друга, их нужно запускать параллельно.

    Promise.all

    Promise.all запускает все промисы одновременно и ждёт, пока все завершатся. Если хотя бы один отклоняется — отклоняется весь результат.

    async function loadDashboard(userId) {
      // Неэффективно: запросы выполняются последовательно (3 секунды)
      // const user = await fetchUser(userId);
      // const stats = await fetchStats(userId);
      // const notifications = await fetchNotifications(userId);
    
      // Эффективно: запросы выполняются параллельно (1 секунда)
      const [user, stats, notifications] = await Promise.all([
        fetchUser(userId),
        fetchStats(userId),
        fetchNotifications(userId),
      ]);
    
      return { user, stats, notifications };
    }
    

    Promise.allSettled

    Promise.allSettled ждёт завершения всех промисов, независимо от того, выполнены они или отклонены. Полезен когда нужны все результаты, даже при частичных ошибках.

    async function loadOptionalData(userId) {
      const results = await Promise.allSettled([
        fetchUser(userId),
        fetchRecommendations(userId), // Необязательные данные
        fetchBadges(userId),          // Необязательные данные
      ]);
    
      // Проверяем статус каждого результата
      const [userResult, recsResult, badgesResult] = results;
    
      return {
        user: userResult.status === 'fulfilled' ? userResult.value : null,
        recommendations: recsResult.status === 'fulfilled' ? recsResult.value : [],
        badges: badgesResult.status === 'fulfilled' ? badgesResult.value : [],
      };
    }
    

    Promise.race и Promise.any

    async function fetchWithTimeout(url, timeoutMs) {
      // Возвращает результат того промиса, который завершится первым
      const result = await Promise.race([
        fetch(url),
        new Promise((_, reject) =>
          // Отклоняем через заданное время
          setTimeout(() => reject(new Error('Таймаут запроса')), timeoutMs)
        ),
      ]);
      return result;
    }
    

    Частые ошибки

    Забытый await

    Отсутствие await — одна из самых распространённых ошибок. Без него функция вернёт промис, а не значение.

    async function wrongExample() {
      // Ошибка: переменная содержит промис, а не пользователя
      const user = fetchUser(1);
      console.log(user.name); // undefined
    }
    
    async function correctExample() {
      // Правильно: ожидаем выполнения промиса
      const user = await fetchUser(1);
      console.log(user.name); // 'Иван Петров'
    }
    

    await в цикле вместо параллелизма

    // Медленно: каждый запрос ждёт предыдущий
    async function slowLoad(ids) {
      const results = [];
      for (const id of ids) {
        const user = await fetchUser(id); // Блокирует следующую итерацию
        results.push(user);
      }
      return results;
    }
    
    // Быстро: все запросы выполняются параллельно
    async function fastLoad(ids) {
      const promises = ids.map(id => fetchUser(id));
      return await Promise.all(promises);
    }
    

    Потеря контекста ошибки

    async function badErrorHandling() {
      try {
        await riskyOperation();
      } catch (error) {
        // Плохо: теряем оригинальный стек ошибки
        throw new Error('Что-то пошло не так');
      }
    }
    
    async function goodErrorHandling() {
      try {
        await riskyOperation();
      } catch (error) {
        // Хорошо: сохраняем оригинальную ошибку через cause
        throw new Error('Ошибка в riskyOperation', { cause: error });
      }
    }
    

    Заключение

    Async/await значительно упрощает работу с асинхронным кодом в JavaScript. Ключевые моменты для запоминания: async-функция всегда возвращает промис, await работает только внутри async-функции, независимые операции стоит запускать параллельно через Promise.all, а ошибки обрабатывать через try/catch.

    Освоив эти паттерны, вы сможете писать чистый, читаемый асинхронный код и избегать классических ошибок производительности.

    Иконка глаза2

    Комментарии

    0

    Постройте личный план изучения Feature-Sliced Design до уровня Middle — бесплатно!

    Feature-Sliced Design — часть карты развития Frontend

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    Angular

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Гарантия
    Бонусы
    иконка звёздочки рейтинга5.0
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Vue 3 и Pinia

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    Nuxt

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга5.0
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста WebSocket: что это и как работает в реальных проектах
    Иконка аватараАнтон
    Иконка календаря24 июня 2026
    websocketjavascriptnodejs+ 3juniorИконка уровня junior

    WebSocket: что это и как работает в реальных проектах

    WebSocket — протокол двусторонней связи в реальном времени. Разбираем, как устроено соединение изнутри, и пишем чат на Node.js с нуля.

    Иконка чипа0
    Иконка глаза110
    Иконка комментариев0
    Картинка поста HTTP методы GET POST PUT DELETE: разница и применение
    Иконка аватараАнтон
    Иконка календаря27 июня 2026
    HTTPRESTAPI+ 2juniorИконка уровня junior

    HTTP методы GET POST PUT DELETE: разница и применение

    HTTP методы GET, POST, PUT, DELETE — основа любого REST API. Разбираем, чем они отличаются, когда применять каждый и какие ошибки допускают новички.

    Иконка чипа0
    Иконка глаза33
    Иконка комментариев0
    Картинка поста SOLID принципы в JavaScript: разбор на примерах
    Иконка аватараАнтон
    Иконка календаря26 июня 2026
    JavaScriptSOLIDООП+ 3middleИконка уровня middle

    SOLID принципы в JavaScript: разбор на примерах

    SOLID принципы в JavaScript — разбираем каждый принцип на реальных примерах кода, чтобы писать чистую и расширяемую архитектуру.

    Иконка чипа0
    Иконка глаза59
    Иконка комментариев0
    Иконка чипа0