Урок 25: Promise и async/await в JavaScript’е

Cегодня разберем одну из тем в JavaScript, это асинхронное программирование с помощью Promise и async/await. Ключевые инструменты для работы с запросами к серверу, обработкой данных и другими операциями, которые требуют времени.

Что такое промисы?

Промисы (Promise) это объекты, которые представляют результат асинхронной операции. Они помогают избежать «ада колбэков» (callback hell) и делают код чище и предсказуемее.

Как работает промис?

У промиса есть три состояния:

  1. Pending — ожидание (начальное состояние).
  2. Fulfilled — успешное выполнение.
  3. Rejected — выполнение с ошибкой.

Промис создается с помощью конструктора new Promise(), который принимает функцию с двумя аргументами: resolve (вызывается при успехе) и reject (при ошибке).

Пример:

const myPromise = new Promise((resolve, reject) => {  
  // Имитация асинхронной операции (например, запрос к серверу)  
  setTimeout(() => {  
    const success = true;  
    if (success) {  
      resolve("Данные успешно получены!");  
    } else {  
      reject("Ошибка загрузки данных!");  
    }  
  }, 2000);  
});

Обработка ошибок через .then() и .catch()

Промисы позволяют обрабатывать результаты и ошибки цепочкой методов.

.then()

Метод then() принимает два аргумента:

  • Функцию для обработки успешного результата.
  • Функцию для обработки ошибки (необязательно, обычно используют .catch()).

Пример:

myPromise  
  .then((result) => {  
    console.log(result); // "Данные успешно получены!"  
  })  
  .catch((error) => {  
    console.error(error); // Сработает при вызове reject()  
  });

Цепочки промисов

Методы можно объединять в цепочки для последовательных операций:

fetchData()  
  .then(processData)  
  .then(displayData)  
  .catch(handleError);

Важно: Если в цепочке возникает ошибка, управление сразу переходит к ближайшему .catch().

Асинхронное программирование с async/await

async/await это синтаксический сахар над промисами, который делает код еще понятнее.

Ключевое слово async

Функция, объявленная с async, всегда возвращает промис:

async function fetchData() {  
  return "Данные загружены!";  
}  

// Аналог:  
function fetchData() {  
  return Promise.resolve("Данные загружены!");  
}

Ключевое слово await

await приостанавливает выполнение функции до выполнения промиса. Работает только внутри async-функций.

Пример:

async function loadData() {  
  try {  
    const result = await myPromise; // Ждем выполнения промиса  
    console.log(result);  
  } catch (error) {  
    console.error(error);  
  }  
}

Обработка ошибок с try/catch

Для обработки ошибок в async/await используйте блок try/catch:

async function loadUser() {  
  try {  
    const user = await fetchUser();  
    const posts = await fetchPosts(user.id);  
    console.log(posts);  
  } catch (error) {  
    console.log("Ошибка:", error);  
  }  
}

Практические задачи

Задача 1: Создайте промис

Напишите промис, который через 3 секунды возвращает случайное число от 1 до 10. Если число больше 5, вызывается resolve, иначе — reject.

Решение:

const numberPromise = new Promise((resolve, reject) => {  
  setTimeout(() => {  
    const num = Math.floor(Math.random() * 10) + 1;  
    if (num > 5) {  
      resolve(`Успех: ${num}`);  
    } else {  
      reject(`Ошибка: ${num}`);  
    }  
  }, 3000);  
});  

numberPromise  
  .then(console.log)  
  .catch(console.error);

Задача 2: Цепочка промисов

Создайте функцию getUserData, которая возвращает промис с объектом пользователя {id: 1, name: "Максим"}. Затем напишите цепочку, которая преобразует имя в верхний регистр.

Решение:

function getUserData() {  
  return Promise.resolve({ id: 1, name: "Максим" });  
}  

getUserData()  
  .then(user => {  
    user.name = user.name.toUpperCase();  
    return user;  
  })  
  .then(updatedUser => console.log(updatedUser));

Задача 3: Перепишите код на async/await

Дана функция fetchData, возвращающая промис. Перепишите цепочку .then() на async/await.

Исходный код:

fetchData()  
  .then(data => processData(data))  
  .then(result => console.log(result))  
  .catch(error => console.error(error));

Решение:

async function handleData() {  
  try {  
    const data = await fetchData();  
    const result = await processData(data);  
    console.log(result);  
  } catch (error) {  
    console.error(error);  
  }  
}  

handleData();

Советы

  1. Всегда обрабатывайте ошибки через .catch() или try/catch.
  2. Избегайте вложенных промисов — используйте цепочки или async/await.
  3. Помните: await можно использовать только в async-функциях.

Промисы и async/await это основа работы с асинхронным кодом в JavaScript. Практикуйтесь на реальных примерах, делайте запросы к API, обрабатывайте файлы и экспериментируйте!

Полный курс «JavaScript для начинающих» доступен здесь: https://max-gabov.ru/javascript-dlya-nachinaushih