Promise.prototype.then()
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!"
});
語法
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 的狀態如何。
onFulfilled 和 onRejected 這兩個處理程式中的一個將被執行,以處理當前 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 未被保留,最終也會耗盡記憶體。
const pendingPromise = new Promise(() => {});
while (true) {
pendingPromise.then(doSomething);
}
如果您對同一個 Promise 物件呼叫兩次 then() 方法(而不是鏈式呼叫),那麼這個 Promise 物件將有兩對 settlement 處理程式。附加到同一 Promise 物件的每個處理程式始終按照它們被新增的順序呼叫。此外,每次呼叫 then() 返回的兩個 Promise 會啟動獨立的鏈,並且不會等待彼此的 settlement。
在 then() 鏈中出現的 Thenable 物件總是會被 resolved — onFulfilled 處理程式永遠不會接收到一個 thenable 物件,並且任何由這兩個處理程式之一返回的 thenable 在傳遞給下一個處理程式之前都會被 resolved。這是因為在構造新的 Promise 時,executor 傳遞的 resolve 和 reject 函式會被儲存,噹噹前 Promise settle 時,相應的函式將被用 fulfillment 值或 rejection reason 呼叫。resolving 邏輯來自 Promise() 建構函式傳遞的 resolve 函式。
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,那麼鏈式呼叫中的後續 then 將會獲得一個等效的 Promise。下面的程式碼片段使用 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
});
如果函式丟擲錯誤或返回一個 rejected Promise,then 呼叫返回一個最終 rejected 的 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() 來處理 rejected Promises,而不是 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 最終會 fulfill。在下面的示例中,第一個 then() 返回 42,該值被包裝在一個 fulfilled Promise 中,即使鏈中的前一個 Promise 被 rejected。
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。
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 之上。
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® 2026 語言規範 # sec-promise.prototype.then |
瀏覽器相容性
載入中…