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.

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

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

    Комментарии

    0

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

    Neovim - практика и настройка — часть карты развития Frontend, Backend, DevOps

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

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

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

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

    React и Redux Toolkit

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

    Zustand

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

    Next.js - с нуля

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

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

    Картинка поста Async await в JavaScript: подробный разбор с примерами
    Иконка аватараАнтон
    Иконка календаря19 июля 2026
    JavaScriptasync/awaitасинхронность+ 3middleИконка уровня middle

    Async await в JavaScript: подробный разбор с примерами

    Разбираем async/await в JavaScript с нуля: как работает синтаксис, обработка ошибок через try/catch, параллельные запросы с Promise.all и частые ошибки

    Иконка чипа0
    Иконка глаза642
    Иконка комментариев0
    Картинка поста GraphQL vs REST: что выбрать для API в 2026 году
    Иконка аватараАнтон
    Иконка календаря11 июля 2026
    graphqlrestapi+ 3middleИконка уровня middle

    GraphQL vs REST: что выбрать для API в 2026 году

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

    Иконка чипа0
    Иконка глаза741
    Иконка комментариев0
    Картинка поста Регулярные выражения в JavaScript: полное руководство
    Иконка аватараАнтон
    Иконка календаря06 августа 2026
    JavaScriptрегулярные выраженияregexp+ 2middleИконка уровня middle

    Регулярные выражения в JavaScript: полное руководство

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

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