Promise.prototype.then()

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

Promise 实例的 then() 方法最多接受两个参数:用于 Promise 的 fulfilled(已fulfilled)和 rejected(已rejected)情况的回调函数。它将这些回调函数存储在调用它的 Promise 对象中,并立即返回另一个 Promise 对象,允许你 链式调用 其他 Promise 方法。

试一试

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

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

语法

js
then(onFulfilled)
then(onFulfilled, onRejected)

参数

onFulfilled

当此 Promise 变为 fulfilled 时异步执行的函数。其返回值将成为 then() 返回的 Promise 的 fulfillment 值。该函数以以下参数被调用:

value

Promise fulfilled 时的值。

如果它不是一个函数,它会被内部替换为一个恒等函数(x) => x),该函数仅将 fulfillment 值向前传递。

onRejected 可选

当此 Promise 变为 rejected 时异步执行的函数。其返回值将成为 then() 返回的 Promise 的 fulfillment 值。该函数以以下参数被调用:

reason

Promise rejected 时的值。

如果它不是一个函数,它会被内部替换为一个抛出函数(x) => { throw x; }),该函数会抛出它接收到的 rejection reason。

返回值

立即返回一个新的 Promise。这个返回的 Promise 在返回时始终处于 pending(等待)状态,无论当前 Promise 的状态如何。

onFulfilledonRejected 这两个处理程序中的一个将被执行,以处理当前 Promise 的 fulfillment 或 rejection。即使当前 Promise 已经 settled(已定型),调用也总是异步发生的。then() 返回的 Promise(在以下列表中称为 p)的行为取决于处理程序的执行结果,遵循一套特定的规则。如果处理函数

  • 返回一个值:p 将以返回的值作为其值而被 fulfilled。
  • 不返回任何东西:p 将以 undefined 作为其值而被 fulfilled。
  • 抛出一个错误:p 将以抛出的错误作为其值而被 rejected。
  • 返回一个已 fulfilled 的 Promise:p 将以该 Promise 的值作为其值而被 fulfilled。
  • 返回一个已 rejected 的 Promise:p 将以该 Promise 的值作为其值而被 rejected。
  • 返回另一个 pending 的 Promise:p 将保持 pending 状态,并在该 Promise 变为 fulfilled/rejected 后,立即以该 Promise 的值作为其值而被 fulfilled/rejected。

描述

then() 方法为 Promise 的最终完成(fulfilled 或 rejected)安排回调函数。它是 Promise 的基本方法:thenable 协议要求所有类 Promise 对象都公开一个 then() 方法,而 catch()finally() 方法都通过调用对象的 then() 方法来工作。

有关 onRejected 处理程序的更多信息,请参阅 catch() 参考。

then() 返回一个新的 Promise 对象,但会修改调用它的 Promise 对象,将处理程序附加到内部列表中。因此,处理程序会被原始 Promise 保留,其生命周期至少与原始 Promise 的生命周期一样长。例如,下面的示例即使返回的 Promise 未被保留,最终也会耗尽内存。

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

如果您对同一个 Promise 对象调用两次 then() 方法(而不是链式调用),那么这个 Promise 对象将有两对 settlement 处理程序。附加到同一 Promise 对象的每个处理程序始终按照它们被添加的顺序调用。此外,每次调用 then() 返回的两个 Promise 会启动独立的链,并且不会等待彼此的 settlement。

then() 链中出现的 Thenable 对象总是会被 resolvedonFulfilled 处理程序永远不会接收到一个 thenable 对象,并且任何由这两个处理程序之一返回的 thenable 在传递给下一个处理程序之前都会被 resolved。这是因为在构造新的 Promise 时,executor 传递的 resolvereject 函数会被保存,当当前 Promise settle 时,相应的函数将被用 fulfillment 值或 rejection reason 调用。resolving 逻辑来自 Promise() 构造函数传递的 resolve 函数。

then() 支持子类继承,这意味着它可以被 Promise 的子类实例调用,结果将是该子类类型的 Promise。你可以通过 [Symbol.species] 属性来自定义返回值的类型。

示例

使用 then() 方法

js
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!
  },
);

将非函数作为参数

js
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,那么链式调用中的后续 then 将会获得一个等效的 Promise。下面的代码片段使用 setTimeout 函数模拟了异步代码。

js
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 然后再解析。

js
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
});

如果函数抛出错误或返回一个 rejected Promise,then 调用返回一个最终 rejected 的 Promise。

js
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() 来处理 rejected Promises,而不是 then() 的两部分语法,如下例所示。

js
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 最终会 fulfill。在下面的示例中,第一个 then() 返回 42,该值被包装在一个 fulfilled Promise 中,即使链中的前一个 Promise 被 rejected。

js
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 的最终状态而被 fulfilled/rejected。

js
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'
  },
);

你可以使用链式调用来实现一个函数,该函数建立在另一个基于 Promise 的 API 之上。

js
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 方法的异步性。

js
// 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® 2026 语言规范
# sec-promise.prototype.then

浏览器兼容性

另见