Promise.then: примеры (JAVASCRIPT)

Метод then в JavaScript: примеры и особенности применения
Раздел: Асинхронность, Цепочки
Promise.then(onFulfilled (function), onRejected (function)): Promise

Базовое описание метода

Метод then() является частью объекта Promise в JavaScript. Он используется для обработки результатов выполнения асинхронных операций после их завершения.

Метод вызывается, когда промис переходит в состояние fulfilled (успешно выполнен) или rejected (выполнен с ошибкой).

Аргументы метода

onFulfilled (необязательный) - функция, которая вызывается при успешном выполнении промиса. Принимает один аргумент - результат выполнения промиса.

onRejected (необязательный) - функция, которая вызывается при отклонении промиса. Принимает один аргумент - причину отклонения (ошибку).

Возвращаемое значение

Метод возвращает новый объект Promise, что позволяет создавать цепочки вызовов. Возвращаемый промис разрешается со значением, которое вернула вызванная функция-обработчик.

Простые примеры использования

Пример с обработкой успешного выполнения:

const promise = new Promise((resolve) => {
  setTimeout(() => resolve('Данные получены'), 1000);
});

promise.then(
  (result) => {
    console.log(result);
    return result + ' и обработаны';
  }
).then(result => console.log(result));
Данные получены
Данные получены и обработаны

Пример с обработкой ошибки:

const failingPromise = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error('Ошибка загрузки')), 1000);
});

failingPromise.then(
  result => console.log('Успех:', result),
  error => console.log('Ошибка перехвачена:', error.message)
);
Ошибка перехвачена: Ошибка загрузки

Пример с одним обработчиком:

Promise.resolve(42)
  .then(value => value * 2)
  .then(value => console.log('Результат:', value));
Результат: 84

Похожие методы в JavaScript

Promise.catch() - специализированный метод для обработки ошибок. Рекомендуется использовать вместо второго аргумента then для улучшения читаемости кода.

promise
  .then(result => process(result))
  .catch(error => handleError(error));

Promise.finally() - выполняется независимо от результата промиса. Полезен для очистки ресурсов.

Async/await - синтаксический сахар над промисами, позволяющий писать асинхронный код в синхронном стиле. Используется для упрощения сложных цепочек then.

Аналоги в других языках программирования

Python (asyncio):

import asyncio

async def main():
    result = await some_async_function()
    print(result)

asyncio.run(main())

PHP (Promises для Guzzle):

$promise = $client->requestAsync('GET', 'https://example.com');
$promise->then(
    function ($response) {
        echo $response->getStatusCode();
    }
);

C# (Task.ContinueWith):

Task.Run(() => SomeWork())
    .ContinueWith(task => {
        Console.WriteLine(task.Result);
    });

Kotlin (Coroutines):

GlobalScope.launch {
    val result = async { fetchData() }.await()
    println(result)
}

Типичные ошибки

Забытый возврат значения из обработчика:

Promise.resolve(5)
  .then(value => {
    value * 2;  // Ошибка: нет return
  })
  .then(result => console.log(result));  // undefined
undefined

Необработанные ошибки в цепочке:

Promise.reject(new Error('Ошибка'))
  .then(result => console.log(result))
  .then(() => console.log('Этот код не выполнится'));

Использование then для уже завершенного промиса:

const promise = Promise.resolve('данные');
setTimeout(() => {
  promise.then(result => console.log(result));  // Сработает
}, 1000);

Изменения в последних версиях

В современных версиях JavaScript метод then не претерпел существенных изменений. Основные улучшения связаны с интеграцией с async/await синтаксисом.

В ES2022 улучшена трассировка стека для асинхронных операций, что упрощает отладку цепочек then.

Спецификация продолжает гарантировать микротасковую очередь для обратных вызовов then, обеспечивая детерминированный порядок выполнения.

Расширенные примеры

Параллельная обработка нескольких промисов:

Пример javascript
const fetchUser = fetch('/api/user');
const fetchPosts = fetch('/api/posts');

Promise.all([fetchUser, fetchPosts])
  .then(responses => 
    Promise.all(responses.map(r => r.json()))
  )
  .then(([user, posts]) => {
    console.log('Пользователь:', user);
    console.log('Посты:', posts);
  });

Динамическая цепочка обработки:

Пример javascript
function processData(data) {
  return Promise.resolve(data)
    .then(validate)
    .then(enrich)
    .then(transform)
    .then(result => {
      console.log('Обработка завершена:', result);
      return result;
    });
}

Обработка с таймаутом:

Пример javascript
function withTimeout(promise, timeout) {
  return Promise.race([
    promise,
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error('Таймаут')), timeout)
    )
  ]);
}

withTimeout(fetch('/api/data'), 5000)
  .then(response => response.json())
  .catch(error => console.error('Ошибка:', error));

Трансформация ошибок:

Пример javascript
apiCall()
  .then(data => process(data))
  .catch(error => {
    if (error.status === 404) {
      return getDefaultData();
    }
    throw error;
  })
  .then(data => console.log('Результат:', data));

Обработка с сайд-эффектами:

Пример javascript
let cache = {};

function getCachedData(key) {
  if (cache[key]) {
    return Promise.resolve(cache[key]);
  }
  
  return fetchData(key)
    .then(data => {
      cache[key] = data;
      return data;
    });
}

JS Promise.then function comments

En
Promise.then Attaches callbacks for promise resolution/rejection