Promise.prototype.then()

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.

Promise 实例的 then() 方法最多接受两个参数:Promise 的已完成和已拒绝案例的回调函数。它立即返回另一个 Promise 对象,允许你对其他承诺方法进行 chain 调用。

¥The then() method of Promise instances takes up to two arguments: callback functions for the fulfilled and rejected cases of the Promise. It immediately returns another Promise object, allowing you to chain calls to other promise methods.

Try it

语法

¥Syntax

js
then(onFulfilled)
then(onFulfilled, onRejected)

参数

¥Parameters

onFulfilled

当这个承诺实现时异步执行的函数。它的返回值成为 then() 返回的 promise 的履行值。使用以下参数调用该函数:

value

兑现承诺的价值。

如果它不是函数,则在内部将其替换为恒等函数 ((x) => x),该函数仅向前传递履行值。

onRejected Optional

当此 Promise 被拒绝时异步执行的函数。它的返回值成为 then() 返回的 promise 的履行值。使用以下参数调用该函数:

reason

承诺被拒绝的值。

如果它不是一个函数,它会在内部被替换为抛出函数((x) => { throw x; }),抛出它收到的拒绝原因。

返回值

¥Return value

立即返回新的 Promise。无论当前 Promise 的状态如何,该新 Promise 在返回时始终处于待处理状态。

¥Returns a new Promise immediately. This new promise is always pending when returned, regardless of the current promise's status.

将执行 onFulfilledonRejected 处理程序之一来处理当前承诺的履行或拒绝。即使当前的 Promise 已经解决,调用也总是异步发生。返回的 Promise(称为 p)的行为取决于处理程序的执行结果,遵循一组特定的规则。如果处理函数:

¥One of the onFulfilled and onRejected handlers will be executed to handle the current promise's fulfillment or rejection. The call always happens asynchronously, even when the current promise is already settled. The behavior of the returned promise (call it p) depends on the handler's execution result, following a specific set of rules. If the handler function:

  • 返回一个值:p 以返回值作为其值来实现。
  • 不返回任何内容:pundefined 作为其值得到满足。
  • 抛出错误:p 被拒绝,并以抛出的错误作为其值。
  • 返回一个已经履行的承诺:p 以该承诺的价值作为其价值来实现。
  • 返回一个已经被拒绝的承诺:p 被拒绝,并以该承诺的值作为其值。
  • 返回另一个待处理的承诺:p 处于待处理状态,并在该承诺履行/拒绝后立即履行/拒绝该承诺的值作为其值。

描述

¥Description

then() 方法为 Promise 的最终完成(履行或拒绝)安排回调函数。这是 Promise 的原始方法:thenable 协议期望所有类似 Promise 的对象公开 then() 方法,而 catch()finally() 方法都通过调用对象的 then() 方法来工作。

¥The then() method schedules callback functions for the eventual completion of a Promise — either fulfillment or rejection. It is the primitive method of promises: the thenable protocol expects all promise-like objects to expose a then() method, and the catch() and finally() methods both work by invoking the object's then() method.

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

¥For more information about the onRejected handler, see the catch() reference.

then() 返回一个新的 Promise 对象。如果你对同一个 Promise 对象调用 then() 方法两次(而不是链接),则该 Promise 对象将具有两对结算处理程序。附加到同一 Promise 对象的所有处理程序始终按照添加顺序进行调用。而且,每次调用 then() 返回的两个 Promise 都启动单独的链,并且不等待彼此的结算。

¥then() returns a new promise object. If you call the then() method twice on the same promise object (instead of chaining), then this promise object will have two pairs of settlement handlers. All handlers attached to the same promise object are always called in the order they were added. Moreover, the two promises returned by each call of then() start separate chains and do not wait for each other's settlement.

沿 then() 链出现的 特纳布尔 对象始终是 resolvedonFulfilled 处理程序永远不会接收 thenable 对象,并且任一处理程序返回的任何 thenable 始终在传递到下一个处理程序之前解析。这是因为在构造新的 Promise 时,会保存 executor 传递的 resolvereject 函数,并且当当前 Promise 结算时,将使用履行值或拒绝原因调用相应的函数。解析逻辑来自 Promise() 构造函数传递的 resolve 函数。

¥Thenable objects that arise along the then() chain are always resolved — the onFulfilled handler never receives a thenable object, and any thenable returned by either handler are always resolved before being passed to the next handler. This is because when constructing the new promise, the resolve and reject functions passed by the executor are saved, and when the current promise settles, the respective function will be called with the fulfillment value or rejection reason. The resolving logic comes from the resolve function passed by the Promise() constructor.

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

¥then() supports subclassing, which means it can be called on instances of subclasses of Promise, and the result will be a promise of the subclass type. You can customize the type of the return value through the [Symbol.species] property.

示例

¥Examples

使用 then() 方法

¥Using the then() method

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

将非函数作为任一参数

¥Having a non-function as either parameter

js
Promise.resolve(1).then(2).then(console.log); // 1
Promise.reject(1).then(2, 2).then(console.log, console.log); // 1

链接

¥Chaining

then 方法返回一个新的 Promise,它允许方法链接。

¥The then method returns a new Promise, which allows for method chaining.

如果作为处理程序传递给 then 的函数返回 Promise,则等效的 Promise 将暴露给方法链中后续的 then。下面的代码片段使用 setTimeout 函数模拟异步代码。

¥If the function passed as handler to then returns a Promise, an equivalent Promise will be exposed to the subsequent then in the method chain. The below snippet simulates asynchronous code with the setTimeout function.

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() 相同。这意味着支持 可用对象,如果返回值不是承诺,则它会隐式封装在 Promise 中,然后解析。

¥The value returned from then() is resolved in the same way as Promise.resolve(). This means thenable objects are supported, and if the return value is not a promise, it's implicitly wrapped in a Promise and then resolved.

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

then 调用返回一个 Promise,如果函数抛出错误或返回被拒绝的 Promise,该 Promise 最终会被拒绝。

¥A then call returns a promise that eventually rejects if the function throws an error or returns a 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() 拒绝的 Promise,而不是 then() 的两种情况语法,如下所示。

¥In practice, it is often desirable to catch() rejected promises rather than then()'s two-case syntax, as demonstrated below.

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

在所有其他情况下,返回的承诺最终都会实现。在以下示例中,第一个 then() 返回封装在已完成的 Promise 中的 42,即使链中的前一个 Promise 被拒绝。

¥In all other cases, the returned promise eventually fulfills. In the following example, the first then() returns 42 wrapped in a fulfilled Promise, even though the previous Promise in the chain was rejected.

js
Promise.reject()
  .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 的最终状态来实现/拒绝。

¥If onFulfilled returns a promise, the return value of then will be fulfilled/rejected based on the eventual state of that promise.

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

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

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

你可以使用链接在另一个此类函数之上使用基于 Promise 的 API 来实现一个函数。

¥You can use chaining to implement one function with a Promise-based API on top of another such function.

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() 的异步性

¥Asynchronicity of then()

下面通过一个例子来演示 then 方法的异步性。

¥The following is an example to demonstrate the asynchronicity of the then method.

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}

规范

Specification
ECMAScript Language Specification
# sec-promise.prototype.then

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看