忘了拆開 Async function 的 Promise 糖衣

Async function Promise
Async function Promise
Async function Promise
...

在專案中巢狀拋接 Promise 可以說是串接 API 的日常,但處理過幾次 await 承接到的結果卻 return 出一個 Promise 而非想要的資料本身,終於要來好好了解背後的原因了!

Async function 的特色

Async Await 是 ES6 釋出的新方法,用簡潔的手法處理 Promise 的資料拋接,比 then() 的寫法更加清楚易懂。
以下範例說明呼叫 async function B 時變數 C 承接的結果仍然是 Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
async function B () {
async function A () {
return new Promise ((resolve, reject) => {
resolve('A');
reject('B');
})
}

try {
const res = await A();
return res;
} catch (error) {

}
}
let C = B()
console.log(C) // ----> promise {}

可以參考這篇的說明,有提到:

由於 async 函式總是返回一個 Promise 對象,如果要獲取該 Promise 的解析值,可以使用 .then() 方法。

Await 的作用

是作為暫停 async 執行等到 Promise 完成並回傳結果用,但以上的案例是最外層 B()async 函式又基於其特性將 res 包裹為一個 Promise

如何取得 Promise 值

使用 then

Promisethenable 對象,可以透過 then 拆解出結果值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
async function B () {
async function A () {
return new Promise ((resolve, reject) => {
resolve('A');
reject('B');
})
}

try {
const res = await A();
return res;
} catch (error) {

}
}

let C;

B().then((res) => {
C = res
console.log(C) // -----> 'A'
});

Async function 包裹並使用 await 拆開

簡而言之 Async 可以作為 Promise 專屬作用域看待,範圍內可以使用 await 取得結果:
參考MDN 官方說明

处理的行为与 Promise.resolve() 一致,不属于原生 Promise 的值全都会被隐式地转换为 Promise 实例后等待

補充

Await 對執行順序的影響

當 Async 函式程序執行到 await時,該行程序的後方都會變為異步執行被推送至事件循環中的一個微任務中,參考MDN 官方說明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
async function foo(name) {
console.log(name, "start");
await console.log(name, "middle");
console.log(name, "end");
}

foo("First");
foo("Second");

// First start
// First middle
// Second start
// Second middle
// First end
// Second end

對應到 Promise 的 then() 寫法相當於將後方程序推送至下一個待執行的微任務(Micro Task):

1
2
3
4
5
6
7
8
function foo(name) {
return new Promise((resolve) => {
console.log(name, "start");
resolve(console.log(name, "middle"));
}).then(() => {
console.log(name, "end");
});
}