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.

then() 方法回傳一個 Promise 物件。它接收兩個引數: Promise 在成功及失敗情況時的回呼函式。

備註: 如果有一個或兩個引數被省略,或為非函式(non-functions),則 then 將處於遺失 handler(s) 的狀態,但不會產生錯誤。若發起 thenPromise 採取了一個狀態(實現(fulfillment)或拒絕(rejection))then 沒有處理它的函式,一個不具有額外 handlers 的新 Promise 物件將被建立,單純採取原 Promise 其最終狀態。

語法

js
p.then(onFulfilled[, onRejected]);

p.then(function(value) {
  // fulfillment
}, function(reason) {
  // rejection
});

參數

onFulfilled

一個 Function,當 Promise 被實現(fulfilled)時被呼叫。此函式接收一個實現值(fulfillment value)作為引數。

onRejected 選擇性

一個 Function,當 Promise 被拒絕(rejected)時被呼叫。此函式接收一個失敗訊息(rejection reason)作為引數。

回傳值

一個進入擱置(pending)狀態的 Promise。(只要堆疊一空)handler 函式非同步地(asynchronously)被呼叫。在調用 handler 後,若 handler 函式:

  • 回傳一個值,則 then 回傳之 promise 以此值被實現(resolved)。
  • 拋出一個例外,則 then 回傳之 promise 以此例外被否決(rejected)。
  • 回傳一個被實現的 promise,則 then 回傳之 promise 以此值被實現。
  • 回傳一個被否決的 promise,則 then 回傳之 promise 以此值被否決。
  • 回傳另一個被擱置的 promise 物件,則 then 回傳之 promise 之實現/拒絕隨後由處理函式之實現/否決決定。並且,then 回傳之 promise 將與處理函式回傳之 promise 以相同值被解決。

以下例子展示 then 方法的非同步性質(asynchronicity)。

js
// 使用一個已實現的 promise,'then' 區塊將立即被觸發,但是它的 handlers 將是非同步地被觸發,如同 console.logs 所示
var resolvedProm = Promise.resolve(33);

var thenProm = resolvedProm.then(function (value) {
  console.log("我在 main stack 之後被呼叫。收到及將回傳的值為:" + value);
  return value;
});
// 立即紀錄 thenProm
console.log(thenProm);

// 我們可以使用 setTimeout 以延遲(postpone)函式執行直到堆疊為空
setTimeout(function () {
  console.log(thenProm);
});

// 紀錄結果,依序為:
// Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// "我在 main stack 之後被呼叫。收到及將回傳的值為:33"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33}

描述

因為 thenPromise.prototype.catch() 方法都回傳 promises,它們可以被串接 — 稱為組合(composition)。

範例

運用 then 方法

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

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

串接

then 方法回傳一個 Promise 而可以進行方法串接(method chaining)。

如果傳入 then 的 handler 函式回傳一個 promise,一個等價的 Promise 將被展現給方法串接中的下一個 then 。以下程式碼片段透過 setTimout 函式模擬非同步程式碼。

js
Promise.resolve("foo")
  // 1. Receive "foo" concatenate "bar" to it and resolve that to the next then
  .then(function (string) {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        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 return the unworked on
  // string to the next then
  .then(function (string) {
    setTimeout(function () {
      string += "baz";
      console.log(string);
    }, 1);
    return string;
  })
  // 3. print helpful messages about how the code in this section will be run
  // before string is actually processed by the mocked asynchronous code in the
  // prior then block.
  .then(function (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);
  });

當 handler 僅回傳一個值,實際上它將回傳 Promise.resolve(<value returned by whichever handler was called>).

js
var p2 = new Promise(function (resolve, reject) {
  resolve(1);
});

p2.then(function (value) {
  console.log(value); // 1
  return value + 1;
}).then(function (value) {
  console.log(value + "- This synchronous usage is virtually pointless"); // 2- This synchronous usage is virtually pointless
});

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

若函式拋出一個錯誤或回傳一個被否決的 Promise,then 也將回傳一個被否決的 Promise。

js
Promise.resolve()
  .then(() => {
    // 使 .then() 回傳一個被否決的 Promise
    throw "Oh no!";
  })
  .then(
    () => {
      console.log("Not called.");
    },
    (reason) => {
      console.error("onRejected function called: ", reason);
    },
  );

在所有其他情形,實現中的 Promise 被回傳。在以下例子中,第一個 then() 將回傳一個實現中包裹 42 的 promise,即使串接中的前一個 Promise 被否決。

js
Promise.reject()
  .then(
    () => 99,
    () => 42,
  ) // onRejected returns 42 which is wrapped in a resolving Promise
  .then((solution) => console.log("Resolved with " + solution)); // Resolved with 42

實務上,使用 catch 捕捉被否決的 promise 較理想的,而不建議使用兩個引數 then 語法,如下展示。

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

你也可以透過串接實作一個 Promise-based API 函式,基於它本身。

js
function fetch_current_data() {
  // 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();
    }
    var j = response.json();
    // maybe do something with j
    return j; // fulfillment value given to user of
    // fetch_current_data().then()
  });
}

onFulfilled 回傳一個 promise,則 then 的實現/否決將取決它。

js
function resolveLater(resolve, reject) {
  setTimeout(function () {
    resolve(10);
  }, 1000);
}
function rejectLater(resolve, reject) {
  setTimeout(function () {
    reject(20);
  }, 1000);
}

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

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

規範

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

瀏覽器相容性

Report problems with this compatibility data on GitHub
desktopmobileserver
Chrome
Edge
Firefox
Opera
Safari
Chrome Android
Firefox for Android
Opera Android
Safari on iOS
Samsung Internet
WebView Android
WebView on iOS
Deno
Node.js
then()

Legend

Tip: you can click/tap on a cell for more information.

Full support
Full support

參見