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

Что используешь then catch или try catch?

1.2 Junior🔥 131 комментариев
#JavaScript Core

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

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

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

Выбор между then/catch и try/catch в современном JavaScript

Этот вопрос затрагивает фундаментальное различие между двумя парадигмами обработки асинхронного кода в JavaScript. Мой выбор зависит от контекста, но в современной фронтенд-разработке я предпочитаю async/await с try/catch для большинства сценариев, сохраняя then/catch для специфических случаев.

Основные различия парадигм

Promise с then/catch (Цепочки промисов)

// Классический подход с цепочками промисов
fetch('/api/data')
  .then(response => {
    if (!response.ok) throw new Error('Network error');
    return response.json();
  })
  .then(data => {
    return processData(data);
  })
  .then(processed => {
    updateUI(processed);
  })
  .catch(error => {
    console.error('Ошибка:', error);
    showErrorToUser(error.message);
  })
  .finally(() => {
    hideLoader();
  });

Преимущества then/catch:

  • Явная цепочка преобразований - чётко видно поток данных
  • Однократная обработка ошибок - один catch обрабатывает все ошибки в цепочке
  • Совместимость - работает везде, где поддерживаются Promise

Async/await с try/catch (Синтаксический сахар)

// Современный подход с async/await
async function loadData() {
  try {
    const response = await fetch('/api/data');
    if (!response.ok) throw new Error('Network error');
    
    const data = await response.json();
    const processed = await processData(data);
    
    updateUI(processed);
  } catch (error) {
    console.error('Ошибка:', error);
    showErrorToUser(error.message);
  } finally {
    hideLoader();
  }
}

Преимущества async/await:

  • Синхронный стиль - код читается линейно, как синхронный
  • Локальная обработка ошибок - try/catch знаком по синхронному коду
  • Упрощение сложных цепочек - особенно при нескольких зависимых асинхронных операциях

Когда что использовать

Когда предпочитаю async/await с try/catch:

  1. Сложные бизнес-логики с несколькими зависимыми асинхронными операциями:
async function checkoutProcess(userId, cartItems) {
  try {
    // Эти операции зависят друг от друга
    const user = await getUser(userId);
    const stock = await checkStock(cartItems);
    const payment = await processPayment(user, cartItems);
    const order = await createOrder(payment.id);
    
    return order;
  } catch (error) {
    // Централизованная обработка разных типов ошибок
    if (error instanceof PaymentError) {
      await notifyPaymentFailed(userId);
    }
    throw error;
  }
}
  1. Обработка параллельных операций с одновременным ожиданием:
async function loadDashboard() {
  try {
    // Параллельное выполнение с деструктуризацией
    const [user, notifications, preferences] = await Promise.all([
      fetchUser(),
      fetchNotifications(),
      fetchPreferences()
    ]);
    
    return { user, notifications, preferences };
  } catch (error) {
    // Можно обработать частичные успехи
    return getFallbackData();
  }
}

Когда then/catch остаётся полезным:

  1. Однострочные операции или простые цепочки:
// Лаконично и читаемо
fetchConfig()
  .then(config => initializeApp(config))
  .catch(() => initializeAppWithDefaults());
  1. Работа с Observable или потоками (в комбинации с RxJS):
fromEvent(button, 'click')
  .pipe(
    switchMap(() => fetchData()),
    catchError(handleError)
  )
  .subscribe(updateUI);
  1. Методы классов, где async/await может быть неудобен:
class DataService {
  loadData() {
    return this.api.fetch()
      .then(data => this.transform(data))
      .catch(error => this.logError(error));
  }
}

Практические рекомендации из опыта

  1. Консистентность в проекте - важнее единообразия, чем абсолютного "правильного" выбора

  2. Гибридный подход для сложных сценариев:

async function complexOperation() {
  // Начало с async/await
  const resource = await acquireResource();
  
  // Затем цепочка преобразований
  return resource.process()
    .then(result => result.optimize())
    .then(optimized => {
      // Дополнительная асинхронная обработка
      return sendToBackend(optimized);
    })
    .catch(error => {
      // Специфичная обработка ошибок для этой цепочки
      logToAnalytics(error);
      throw error;
    });
}
  1. Обработка ошибок разного уровня:
async function nestedOperations() {
  try {
    const data = await fetchData();
    
    // Локальная обработка ошибок для не-критичной операции
    const metadata = await fetchMetadata().catch(() => getDefaultMetadata());
    
    // Основная обработка с возможностью "проброса" ошибки
    return await processWithFallback(data, metadata);
  } catch (error) {
    // Глобальная обработка критических ошибок
    reportCriticalError(error);
    throw error;
  }
}

Производительность и отладка

Важное замечание: несмотря на мифы, современные движки JavaScript (V8, SpiderMonkey) оптимизируют async/await практически без накладных расходов. Ключевые различия:

  • Стек вызовов - async/await сохраняет полный стек, что упрощает отладку
  • Читаемость - особенно важна в командной разработке
  • Ошибки - try/catch ловит синхронные ошибки в async-функциях, что then/catch делает неявно

Моё правило: начинаю с async/await для основной логики, перехожу на then/catch для простых цепочек или специфичных сценариев. Главное — сохранять читаемость и предсказуемость кода, особенно при работе в команде, где другие разработчики должны легко понимать поток выполнения и обработку ошибок.