← Назад к вопросам

Что такое цепочка вызовов Promise?

2.3 Middle🔥 231 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое цепочка вызовов Promise

Цепочка вызовов (Promise chain) — это последовательное выполнение асинхронных операций, где результат одной операции передаётся в следующую. Каждый .then() возвращает новый Promise, позволяя продолжить цепь.

Основной принцип

Каждый .then() получает результат предыдущего Promise и может:

  1. Вернуть результат напрямую
  2. Вернуть новый Promise
  3. Выполнить какую-то операцию
fetch('/api/user')
  .then(response => response.json())           // Парсим JSON
  .then(user => fetch(`/api/posts/${user.id}`)) // Получаем посты
  .then(response => response.json())            // Парсим посты
  .then(posts => console.log(posts))            // Выводим результат
  .catch(error => console.error(error));        // Обрабатываем ошибки

Как работает цепочка

1. Базовый пример

// Функции, возвращающие Promise
const getUser = (id) => 
  new Promise(resolve => {
    setTimeout(() => resolve({ id, name: 'John' }), 1000);
  });

const getUserPosts = (userId) => 
  new Promise(resolve => {
    setTimeout(() => resolve([
      { id: 1, title: 'Post 1' },
      { id: 2, title: 'Post 2' }
    ]), 1000);
  });

// Цепочка вызовов
getUser(1)
  .then(user => {
    console.log('User:', user);
    return getUserPosts(user.id);
  })
  .then(posts => {
    console.log('Posts:', posts);
  })
  .catch(error => console.error('Error:', error));

// Результат:
// User: { id: 1, name: 'John' }
// Posts: [{ id: 1, title: 'Post 1' }, { id: 2, title: 'Post 2' }]

2. Поочередное выполнение

// Функции выполняются последовательно, не параллельно
Promise.resolve()
  .then(() => {
    console.log('Step 1');
    return new Promise(resolve => setTimeout(resolve, 1000));
  })
  .then(() => {
    console.log('Step 2'); // Выполнится через 1 сек
    return new Promise(resolve => setTimeout(resolve, 1000));
  })
  .then(() => {
    console.log('Step 3'); // Выполнится через 2 сек
  });

// Результат:
// Step 1
// Step 2 (через 1 сек)
// Step 3 (через 2 сек)

3. Трансформация данных

fetch('/api/product/1')
  .then(response => response.json())
  .then(product => ({
    ...product,
    price: product.price * 1.2  // Добавляем налог
  }))
  .then(product => ({
    ...product,
    priceFormatted: `$${product.price.toFixed(2)}`  // Форматируем
  }))
  .then(product => {
    console.log('Final product:', product);
  });

Обработка ошибок в цепочке

1. Единый catch для всей цепи

fetch('/api/user')
  .then(response => response.json())
  .then(user => fetch(`/api/posts/${user.id}`))
  .then(response => response.json())
  .then(posts => console.log(posts))
  .catch(error => {
    console.error('Error in chain:', error);
    // Обрабатываем ошибку из любого этапа
  });

2. Перехват ошибки на конкретном этапе

fetch('/api/user')
  .then(response => response.json())
  .catch(error => {
    console.error('Failed to get user:', error);
    return { id: 'default', name: 'Guest' }; // Значение по умолчанию
  })
  .then(user => fetch(`/api/posts/${user.id}`))
  .then(response => response.json())
  .catch(error => {
    console.error('Failed to get posts:', error);
    return [];
  })
  .then(posts => console.log('Posts:', posts));

Promise.all() для параллельных операций

Если операции не зависят друг от друга, выполняй их параллельно:

// Плохо — последовательно (медленно)
getUser(1)
  .then(user => getPosts(user.id))
  .then(posts => getComments(posts[0].id))
  .then(comments => console.log(comments));

// Хорошо — параллельно (быстро)
Promise.all([
  getUser(1),
  getPosts(1),
  getComments(1)
])
  .then(([user, posts, comments]) => {
    console.log(user, posts, comments);
  });

Async/Await — современный способ

Async/await делает цепочку Promise более читаемой:

// Старый способ — then/catch
function loadUserWithPosts(userId) {
  return getUser(userId)
    .then(user => 
      getPosts(user.id).then(posts => ({
        user,
        posts
      }))
    )
    .catch(error => console.error(error));
}

// Новый способ — async/await
async function loadUserWithPosts(userId) {
  try {
    const user = await getUser(userId);
    const posts = await getPosts(user.id);
    return { user, posts };
  } catch (error) {
    console.error(error);
  }
}

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

1. Забыть return в then

// Неправильно — следующий then получит undefined
fetch('/api/user')
  .then(response => response.json())
  .then(user => {
    getUserPosts(user.id); // Забыли return
  })
  .then(posts => console.log(posts)); // posts === undefined

// Правильно
fetch('/api/user')
  .then(response => response.json())
  .then(user => {
    return getUserPosts(user.id);
  })
  .then(posts => console.log(posts));

2. Вложенные цепочки вместо плоских

// Плохо — пирамида
getUser(1).then(user => {
  getPosts(user.id).then(posts => {
    getComments(posts[0].id).then(comments => {
      console.log(comments); // Пирамида смерти
    });
  });
});

// Хорошо — плоская цепочка
getUser(1)
  .then(user => getPosts(user.id))
  .then(posts => getComments(posts[0].id))
  .then(comments => console.log(comments));

Вывод

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

Что такое цепочка вызовов Promise? | PrepBro