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) 的狀態,但不會產生錯誤。若發起 then
之 Promise
採取了一個狀態(實現(fulfillment)
或拒絕(rejection))
而 then
沒有處理它的函式,一個不具有額外 handlers 的新 Promise
物件將被建立,單純採取原 Promise
其最終狀態。
語法
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)。
// 使用一個已實現的 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}
描述
因為 then
和 Promise.prototype.catch()
方法都回傳 promises,它們可以被串接 — 稱為組合(composition)。
範例
運用 then
方法
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
函式模擬非同步程式碼。
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>)
.
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。
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 被否決。
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
語法,如下展示。
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 函式,基於它本身。
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
的實現/否決將取決它。
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 Language Specification # sec-promise.prototype.then |
瀏覽器相容性
BCD tables only load in the browser