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

Какие свойства принимают then, catch и finally?

1.0 Junior🔥 151 комментариев
#JavaScript Core

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

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

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

Свойства then, catch, finally в Promise

Основы Promise

Promise - объект для асинхронных операций. Он может находиться в трёх состояниях:

  1. Pending - операция не завершена
  2. Fulfilled - операция успешно завершена (резолв)
  3. Rejected - операция завершена с ошибкой (отклонена)

then()

then() принимает две колбэк-функции и возвращает новый Promise:

promise.then(
  onFulfilled,  // функция, вызывается при успехе
  onRejected    // функция, вызывается при ошибке (опционально)
)

Параметры onFulfilled:

  • Получает значение (результат) от resolve()
  • Должна вернуть значение или новый Promise
const promise = Promise.resolve(42);

promise.then((value) => {
  console.log(value); // 42
  return value * 2;
}).then((result) => {
  console.log(result); // 84
});

Параметры onRejected:

  • Получает причину ошибки (Rejection reason)
  • Может вернуть значение (переводит в fulfilled) или выбросить ошибку
const promise = Promise.reject(new Error('Ошибка'));

promise.then(
  undefined, // onFulfilled не нужен
  (error) => {
    console.log(error.message); // 'Ошибка'
    return 'Восстановилось'; // Переводит в fulfilled
  }
).then((value) => {
  console.log(value); // 'Восстановилось'
});

Чейнирование then():

fetch('/api/user')
  .then((response) => response.json())
  .then((user) => {
    console.log(user);
    return fetch(`/api/posts/${user.id}`);
  })
  .then((response) => response.json())
  .then((posts) => {
    console.log(posts);
  })
  .catch((error) => console.error(error));

Важно: если onFulfilled или onRejected вернёт Promise, то цепь ждёт его разрешения.

catch()

catch() - это сокращение для .then(undefined, onRejected):

promise.catch(onRejected);
// Эквивалентно:
promise.then(undefined, onRejected);

Параметры catch():

  • Получает причину ошибки
  • Может обработать ошибку и вернуть значение (цепь продолжится с fulfilled)
  • Может выбросить новую ошибку
const promise = Promise.reject(new Error('Сетевая ошибка'));

promise
  .then((data) => data.json())
  .catch((error) => {
    console.error('Перехвачена ошибка:', error.message);
    // Возвращаем значение - цепь продолжится с fulfilled
    return { fallback: true };
  })
  .then((result) => {
    console.log(result); // { fallback: true }
  });

Полезный паттерн - обработка ошибок на разных этапах:

fetch('/api/user')
  .then((response) => {
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    return response.json();
  })
  .catch((error) => {
    console.error('Ошибка загрузки пользователя:', error);
    return null; // Продолжаем цепь с null
  })
  .then((user) => {
    if (user) {
      console.log(user);
    } else {
      console.log('Пользователь не загружен');
    }
  });

finally()

finally() - вызывается ВСЕГДА, независимо от результата (успех или ошибка):

promise.finally(onFinally)

Параметры finally():

  • Не получает никаких параметров
  • Может вернуть значение (обычно не возвращает)
  • Если выбросит ошибку - цепь будет отклонена
  • Не может менять результат Promise (в отличие от then/catch)
let isLoading = true;

fetch('/api/data')
  .then((response) => response.json())
  .then((data) => {
    console.log(data);
  })
  .catch((error) => {
    console.error(error);
  })
  .finally(() => {
    isLoading = false; // Выполнится в любом случае
    console.log('Загрузка завершена');
  });

finally() не меняет результат:

Promise.resolve(42)
  .finally(() => 'new value') // Это значение игнорируется
  .then((value) => {
    console.log(value); // 42, не 'new value'
  });

Promise.reject(new Error('error'))
  .finally(() => 'recovery') // Не восстанавливает
  .catch((error) => {
    console.log(error.message); // 'error'
  });

Практический пример с finally():

function fetchWithSpinner(url) {
  showSpinner();
  
  return fetch(url)
    .then((response) => response.json())
    .then((data) => {
      console.log('Данные получены:', data);
      return data;
    })
    .catch((error) => {
      console.error('Ошибка:', error);
      showError('Не удалось загрузить данные');
      throw error;
    })
    .finally(() => {
      hideSpinner(); // Спиннер скроется в любом случае
    });
}

Сравнение then/catch/finally

МетодПолучает параметрМеняет результатКогда вызывается
then()Да (value или error)ДаПри успехе или ошибке (в зависимости от версии)
catch()Да (error)ДаТолько при ошибке
finally()НетНетВ любом случае

Сложный пример - комбинация

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve({ id: 1, name: 'Alice' });
    } else {
      reject(new Error('Случайная ошибка'));
    }
  }, 1000);
});

promise
  .then((user) => {
    console.log('Пользователь получен:', user);
    return user.id;
  })
  .then((userId) => {
    console.log('ID пользователя:', userId);
    return fetch(`/api/posts/${userId}`);
  })
  .then((response) => response.json())
  .catch((error) => {
    console.error('Ошибка в цепи:', error.message);
    return []; // Возвращаем пустой массив при ошибке
  })
  .finally(() => {
    console.log('Загрузка завершена');
  })
  .then((posts) => {
    console.log('Посты:', posts);
  });

Ключевые выводы

  1. then() - основной метод для работы с результатом или ошибкой
  2. catch() - удобный способ обработки только ошибок
  3. finally() - для очистки ресурсов (закрытие спиннера, логирование и т.д.)
  4. Все три метода возвращают новый Promise, позволяя создавать цепи
  5. Ошибки распространяются вниз по цепи до первого catch()