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.

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

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

    Комментарии

    0

    Постройте личный план изучения Nuxt - fullstack Vue фреймворк до уровня Middle — бесплатно!

    Nuxt - fullstack Vue фреймворк — часть карты развития Frontend

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

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

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

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

    Основы разработки

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга5.0
    бесплатно
    Подробнее
    изображение курса

    Angular

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

    Feature-Sliced Design

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

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

    Картинка поста Алгоритмы и структуры данных: как готовиться к собеседованию
    Иконка аватараАнтон
    Иконка календаря14 сентября 2026
    алгоритмыструктуры данныхсобеседования+ 2middleИконка уровня middle

    Алгоритмы и структуры данных: как готовиться к собеседованию

    Разбираем ключевые алгоритмы и структуры данных, которые чаще всего спрашивают на технических собеседованиях: массивы, хеш-таблицы, деревья, сортировки и сложность алгоритмов.

    Иконка чипа0
    Иконка глаза179
    Иконка комментариев0
    Картинка поста Вопросы на собеседовании Junior Frontend: разбор с примерами кода
    Иконка аватараАнтон
    Иконка календаря13 сентября 2026
    frontendjavascriptсобеседование+ 2juniorИконка уровня junior

    Вопросы на собеседовании Junior Frontend: разбор с примерами кода

    Собеседование Junior Frontend: вопросы по JavaScript, CSS, DOM и асинхронности с примерами кода и разбором частых ошибок кандидатов.

    Иконка чипа0
    Иконка глаза219
    Иконка комментариев0
    Иконка аватараАнтон
    Иконка календаря26 сентября 2026
    Claude CodeAI-инструментыDevOps+ 2middleИконка уровня middle

    Kilo Code в VS Code: установка и настройка из России

    Kilo Code ставится в VS Code из Marketplace за минуту, а спотыкается на следующем шаге: расширению нужен доступ к модели, и штатные способы его получить из России не работают. Рабочая схема выглядит так — поставить расширение, выбрать провайдера Anthropic и подменить ему base URL на прокси, который принимает оплату в рублях. Ниже весь путь целиком: установка, какие поля заполнять в настройках провайдера, как выбрать модель и что проверять, когда агент вместо кода отвечает ошибкой доступа.

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