[英]JavaScript quiz of printing sequence with combination of promise.then and async function
我對使用異步函數執行promise.then
的順序感到困惑。 控制台上顯示的測驗結果是: 1, a, 2, b, c, d, 3, e
。
我在想:
3
只是插入到d
和e
之間?promise.then
插入到任務隊列中,但是為什么呢?Promise.resolve
嗎?這是我對這些假設的測試:
https://codepen.io/allieschen/pen/WNMjgPx
以下是原始測驗代碼:
new Promise((resolve) => {
console.log(1);
resolve();
})
.then(async () => {
console.log(2);
})
.then(async () => {
console.log(3);
});
new Promise((resolve) => {
console.log("a");
resolve();
})
.then(() => {
console.log("b");
})
.then(() => {
console.log("c");
})
.then(() => {
console.log("d");
})
.then(() => {
console.log("e");
});
我已經將調試器與 Node.js 一起使用,它顯示從 b 到 e,它們不斷地遍歷(被解析?)堆棧。 然后程序將返回執行 aync 函數並打印 2。
所以,我希望看到: 1, a, 2, b, c, d, e, 3
。
我非常感謝您對這個問題的任何幫助。
為了回答您的問題,讓我首先嘗試解釋您問題中的代碼是如何執行的。
第一個 promise 構造函數被執行
new Promise((resolve) => { console.log(1); resolve(); })
在控制台上記錄1
並同步解決承諾
當 promise 被解析時,一個作業被排入微任務隊列以執行傳遞給then()
方法的實現處理程序
new Promise((resolve) => { ... }) .then(async () => { console.log(2); })
micro-task queue: [ job(console.log(2)) ] console output: 1
執行第二個 promise 構造函數
new Promise((resolve) => { console.log("a"); resolve(); })
在控制台上記錄'a'
並同步解決承諾
當 promise 被解析時,一個作業被排入微任務隊列以執行傳遞給then()
方法的實現處理程序
new Promise((resolve) => { ... }) .then(async () => { console.log("b"); })
micro-task queue: [ job(console.log(2)), job(console.log('b')) ] console output: 1 a
腳本同步執行結束后,javascript開始處理微任務隊列
micro-task queue: [ job(console.log(2)), job(console.log('b')) ] console output: 1 a
微任務中的第一個作業出列並處理,在控制台上記錄2
micro-task queue: [ job(console.log('b')) ] console output: 1 a 2
由於傳遞給第一個承諾的第一個then()
方法的履行處理程序是一個async
函數,因此履行處理程序隱式返回一個承諾。
如果傳遞給then
方法的回調函數的返回值也是一個promise, then()
方法返回的promise被解析為其回調函數返回的promise。
換句話說,外部promise(由then()方法返回)的命運取決於內部promise(由它的回調函數返回)。 如果內部承諾實現,外部承諾也將以相同的值實現。
以下代碼示例演示了then
方法返回的 promise 如何解析為其回調函數返回的 promise:
const outerPromise = new Promise((resolveOuter, rejectOuter) => { const innerPromise = new Promise((resolveInner, rejectInner) => { resolveInner(); }); // resolve/reject functions of the outer promise are // passed to the `then()` method of the inner promise // as the fulfilment/rejection handlers respectively innerPromise.then(resolveOuter, rejectOuter); });
為了將外部promise解析為內部promise,另一個作業將被排入微任務隊列
micro-task queue: [ job(console.log('b')), job(resolve(outerPr, innerPr) ] console output: 1 a 2
微任務隊列中的下一個作業出列並處理,在控制台上記錄'b'
micro-task queue: [ job(resolve(outerProm, innerProm) ] console output: 1 a 2 b
由於在控制台上記錄'b'
的回調隱式返回 undefined,因此包裝器then()
方法返回的 promise 用undefined
的值實現。
結果,另一個作業在微任務隊列中排隊執行下一個then()
方法的履行處理程序
new Promise((resolve) => { ... }) .then(() => { ... }) .then(() => { console.log("c"); })
micro-task queue: [job(resolve(outerProm, innerProm), job(console.log('c')] console output: 1 a 2 b
微任務隊列中的下一個作業出列並處理。 由於下一項工作與一個等待另一個承諾解決(解決或拒絕)的承諾相關,因此內部承諾使用undefined
的值(由相應的回調函數返回的值)來解決(參見步驟 7)。
結果,另一個作業在微任務隊列中排隊執行內部承諾的履行處理程序。 在這種情況下,履行處理程序是外部承諾的resolve
功能。 調用它將解決外部承諾
micro-task queue: [ job(console.log('c'), job(resolve(outerProm), ] console output: 1 a 2 b
微任務隊列中的下一個作業出列並處理,在控制台上記錄“c”
micro-task queue: [ job(resolve(outerProm), ] console output: 1 a 2 bc
由於在控制台上記錄'c'
的回調隱式返回 undefined,因此包裝器then()
方法返回的 promise 用undefined
的值實現。
結果,另一個作業在微任務隊列中排隊執行下一個then()
方法的履行處理程序
new Promise((resolve) => { ... }) .then(() => { ... }) .then(() => { ... }) .then(() => { console.log("d"); })
micro-task queue: [ job(resolve(outerProm), job(console.log('d') ] console output: 1 a 2 bc
微任務隊列中的下一個作業出列處理,解析第一個promise的then()
方法返回的promise
new Promise((resolve) => { ... }) .then(async () => { console.log(2); })
結果,一個作業被排入微任務隊列以執行其履行處理程序
micro-task queue: [ job(console.log('d'), job(console.log(3) ] console output: 1 a 2 bc
微任務隊列中的下一個作業出列並處理,在控制台上記錄'd'
micro-task queue: [ job(console.log(3) ] console output: 1 a 2 bcd
執行在控制台上記錄'd'
的回調后,另一個作業在微任務隊列中排隊以在控制台上記錄'e'
micro-task queue: [ job(console.log(3), job(console.log('e') ] console output: 1 a 2 bcd
最后,最后兩個作業將出列並一個接一個地處理,最終輸出將是:
micro-task queue: [ ] console output: 1 a 2 bcd 3 e
現在來回答你的問題:
為什么 3 只是插入到 d 和 e 之間?
請參閱上面的詳細說明。
另外,我發現用異步函數實現會每三個promise.then插入到任務隊列中,但是為什么呢?
如果您理解了上面的解釋,那么您現在也理解了 codepen 中的輸出。
用異步函數實現就像返回 Promise.resolve 一樣嗎?
是的。 由於async
函數隱式返回一個承諾,因此從then()
方法的回調函數返回Promise.resolve()
將具有相同的效果(參見上面的步驟 7)。
注意:雖然理解代碼的輸出對於深入理解語言是一件好事,但現實世界的代碼不應該依賴於兩個不同的不相關的承諾鏈中承諾的時間。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.