Spec-Zone.ru › JavaScript

Promise.prototype.then()

Baseline Широко доступно

Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна в браузерах с июля 2015 года.

Метод then() экземпляров Promise принимает до двух аргументов: функций обратного вызова для случаев выполнения (fulfilled) и отклонения (rejected) Promise. Он сохраняет функции обратного вызова в объекте Promise, на котором он был вызван, и немедленно возвращает другой объект Promise, позволяя вам цепочкой вызывать другие методы Promise.

Попробуйте

const promise1 = new Promise((resolve, reject) => {
  resolve("Success!");
});

promise1.then((value) => {
  console.log(value);
  // Expected output: "Success!"
});

Синтаксис

then(onFulfilled)
then(onFulfilled, onRejected)

Параметры

onFulfilled
Функция для асинхронного выполнения, когда этот Promise будет выполнен. Возвращаемое ею значение становится значением выполнения Promise, возвращаемого then(). Функция вызывается со следующими аргументами:
value
Значение, с которым был выполнен Promise.

Если это не функция, она внутренне заменяется функцией-идентичностью ((x) => x), которая просто передает значение выполнения дальше.

onRejected Необязательно
Функция для асинхронного выполнения, когда этот Promise будет отклонен. Возвращаемое ею значение становится значением выполнения Promise, возвращаемого then(). Функция вызывается со следующими аргументами:
reason
Значение, с которым был отклонен Promise.

Если это не функция, она внутренне заменяется функцией-генератором исключений ((x) => { throw x; }), которая генерирует исключение с полученной причиной отклонения.

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

Немедленно возвращает новый Promise. Этот возвращаемый Promise всегда находится в состоянии ожидания при возврате, независимо от текущего состояния исходного Promise.

Один из обработчиков onFulfilled и onRejected будет выполнен для обработки выполнения или отклонения текущего Promise. Вызов всегда происходит асинхронно, даже если текущий Promise уже разрешен (settled). Поведение Promise, возвращаемого then() (далее в списке именуемого p), зависит от результата выполнения обработчика, следуя определенному набору правил. Если функция-обработчик:

  • возвращает значение: p будет выполнен со значением, возвращенным как его значение.
  • ничего не возвращает: p будет выполнен с undefined в качестве своего значения.
  • генерирует исключение: p будет отклонен с сгенерированным исключением в качестве своего значения.
  • возвращает уже выполненный Promise: p будет выполнен со значением этого Promise.
  • возвращает уже отклоненный Promise: p будет отклонен со значением этого Promise.
  • возвращает другой ожидающий Promise: p будет ожидать и будет выполнен/отклонен со значением этого Promise немедленно после того, как этот Promise будет выполнен/отклонен.

Описание

Метод then() планирует выполнение функций обратного вызова для предполагаемого завершения Promise — либо выполнения, либо отклонения. Это примитивный метод Promise: протокол thenable ожидает, что все объекты, похожие на Promise, будут предоставлять метод then(), а методы catch() и finally() работают путем вызова метода then() объекта.

Для получения дополнительной информации об обработчике onRejected см. справочник по catch().

then() возвращает новый объект Promise, но мутирует объект Promise, на котором он был вызван, добавляя обработчики во внутренний список, если Promise находится в ожидании. Следовательно, обработчик сохраняется исходным Promise до тех пор, пока этот Promise остается в ожидании и доступен. Например, следующий пример в конечном итоге приведет к нехватке памяти, даже если возвращаемый Promise не сохраняется:

const pendingPromise = new Promise(() => {});
while (true) {
  pendingPromise.then(doSomething);
}

Если вы вызовете метод then() дважды на одном и том же объекте Promise (вместо цепочки), то этот объект Promise будет иметь две пары обработчиков завершения. Все обработчики, прикрепленные к одному и тому же объекту Promise, всегда вызываются в порядке их добавления. Более того, два Promise, возвращаемые каждым вызовом then(), начинают отдельные цепочки и не ждут завершения друг друга.

Объекты Thenable, возникающие вдоль цепочки then(), всегда разрешаются — обработчик onFulfilled никогда не получает объект thenable, и любой thenable, возвращаемый любым обработчиком, всегда разрешается перед передачей следующему обработчику. Это связано с тем, что при создании нового Promise функции resolve и reject, передаваемые executor, сохраняются, и когда текущий Promise завершается, соответствующая функция будет вызвана со значением выполнения или причиной отклонения. Логика разрешения исходит из функции resolve, передаваемой конструктором Promise().

then() поддерживает подклассинг, что означает, что его можно вызывать для экземпляров подклассов Promise, и результат будет Promise типа подкласса. Тип возвращаемого значения можно настроить через свойство [Symbol.species].

Примеры

Использование метода then()

const p1 = new Promise((resolve, reject) => {
  resolve("Success!");
  // or
  // reject(new Error("Error!"));
});

p1.then(
  (value) => {
    console.log(value); // Success!
  },
  (reason) => {
    console.error(reason); // Error!
  },
);

Наличие не-функции в качестве одного из параметров

Promise.resolve(1).then(2).then(console.log); // 1
Promise.reject(new Error("failed")).then(2, 2).then(console.log, console.log); // Error: failed

Цепочка

Метод then возвращает новый Promise, что позволяет использовать цепочку методов.

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

Promise.resolve("foo")
  // 1. Receive "foo", concatenate "bar" to it, and resolve that to the next then
  .then(
    (string) =>
      new Promise((resolve, reject) => {
        setTimeout(() => {
          string += "bar";
          resolve(string);
        }, 1);
      }),
  )
  // 2. receive "foobar", register a callback function to work on that string
  // and print it to the console, but not before returning the unworked on
  // string to the next then
  .then((string) => {
    setTimeout(() => {
      string += "baz";
      console.log(string); // foobarbaz
    }, 1);
    return string;
  })
  // 3. print helpful messages about how the code in this section will be run
  // before the string is actually processed by the mocked asynchronous code in the
  // previous then block.
  .then((string) => {
    console.log(
      "Last Then: oops... didn't bother to instantiate and return a promise in the prior then so the sequence may be a bit surprising",
    );

    // Note that `string` will not have the 'baz' bit of it at this point. This
    // is because we mocked that to happen asynchronously with a setTimeout function
    console.log(string); // foobar
  });

// Logs, in order:
// Last Then: oops... didn't bother to instantiate and return a promise in the prior then so the sequence may be a bit surprising
// foobar
// foobarbaz

Значение, возвращаемое из then(), разрешается тем же образом, что и Promise.resolve(). Это означает, что объекты thenable поддерживаются, и если возвращаемое значение не является Promise, оно неявно оборачивается в Promise, а затем разрешается.

const p2 = new Promise((resolve, reject) => {
  resolve(1);
});

p2.then((value) => {
  console.log(value); // 1
  return value + 1;
}).then((value) => {
  console.log(value, "- A synchronous value works"); // 2 - A synchronous value works
});

p2.then((value) => {
  console.log(value); // 1
});

Вызов then возвращает Promise, который в конечном итоге отклоняется, если функция генерирует исключение или возвращает отклоненный Promise.

Promise.resolve()
  .then(() => {
    // Makes .then() return a rejected promise
    throw new Error("Oh no!");
  })
  .then(
    () => {
      console.log("Not called.");
    },
    (error) => {
      console.error(`onRejected function called: ${error.message}`);
    },
  );

На практике часто желательно catch() отклоненные Promise, а не двухслучайный синтаксис then(), как показано ниже.

Promise.resolve()
  .then(() => {
    // Makes .then() return a rejected promise
    throw new Error("Oh no!");
  })
  .catch((error) => {
    console.error(`onRejected function called: ${error.message}`);
  })
  .then(() => {
    console.log("I am always called even if the prior then's promise rejects");
  });

Во всех остальных случаях возвращаемый Promise в конечном итоге выполняется. В следующем примере первый then() возвращает 42, завернутый в выполненный Promise, даже если предыдущий Promise в цепочке был отклонен.

Promise.reject(new Error("Oh no!"))
  .then(
    () => 99,
    () => 42,
  ) // onRejected returns 42 which is wrapped in a fulfilled Promise
  .then((solution) => console.log(`Resolved with ${solution}`)); // Fulfilled with 42

Если onFulfilled возвращает Promise, возвращаемое значение then будет выполнено/отклонено на основе окончательного состояния этого Promise.

function resolveLater(resolve, reject) {
  setTimeout(() => {
    resolve(10);
  }, 1000);
}
function rejectLater(resolve, reject) {
  setTimeout(() => {
    reject(new Error("Error"));
  }, 1000);
}

const p1 = Promise.resolve("foo");
// Return promise here, that will be resolved to 10 after 1 second
const p2 = p1.then(() => new Promise(resolveLater));
p2.then(
  (v) => {
    console.log("resolved", v); // "resolved", 10
  },
  (e) => {
    // not called
    console.error("rejected", e);
  },
);

// Return promise here, that will be rejected with 'Error' after 1 second
const p3 = p1.then(() => new Promise(rejectLater));
p3.then(
  (v) => {
    // not called
    console.log("resolved", v);
  },
  (e) => {
    console.error("rejected", e); // "rejected", 'Error'
  },
);

Вы можете использовать цепочку для реализации одной функции с API на основе Promise поверх другой такой функции.

function fetchCurrentData() {
  // The fetch() API returns a Promise. This function
  // exposes a similar API, except the fulfillment
  // value of this function's Promise has had more
  // work done on it.
  return fetch("current-data.json").then((response) => {
    if (response.headers.get("content-type") !== "application/json") {
      throw new TypeError();
    }
    const j = response.json();
    // maybe do something with j

    // fulfillment value given to user of
    // fetchCurrentData().then()
    return j;
  });
}

Асинхронность then()

Ниже приведен пример, демонстрирующий асинхронность метода then.

// Using a resolved promise 'resolvedProm' for example,
// the function call 'resolvedProm.then(...)' returns a new promise immediately,
// but its handler '(value) => {...}' will get called asynchronously as demonstrated by the console.logs.
// the new promise is assigned to 'thenProm',
// and thenProm will be resolved with the value returned by handler
const resolvedProm = Promise.resolve(33);
console.log(resolvedProm);

const thenProm = resolvedProm.then((value) => {
  console.log(
    `this gets called after the end of the main stack. the value received is: ${value}, the value returned is: ${
      value + 1
    }`,
  );
  return value + 1;
});
console.log(thenProm);

// Using setTimeout, we can postpone the execution of a function to the moment the stack is empty
setTimeout(() => {
  console.log(thenProm);
});

// Logs, in order:
// Promise {[[PromiseStatus]]: "resolved", [[PromiseResult]]: 33}
// Promise {[[PromiseStatus]]: "pending", [[PromiseResult]]: undefined}
// "this gets called after the end of the main stack. the value received is: 33, the value returned is: 34"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseResult]]: 34}

Спецификации

Спецификация
ECMAScript® 2027 Language Specification
# sec-promise.prototype.then

Совместимость с браузерами

Настольные компьютеры Мобильные устройства Сервер
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
then
32
12
29
19
8
32
29
19
8
2.0
4.4.3
8
1.0.0
1.0
0.12.0

См. также

  • Promise
  • Promise.prototype.catch()

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API