就在昨天學習了關於 Promise
之後,似乎對 Promise
好像有點了解了,但是又似乎還是有那麼一點不是很清楚!
今天就要從幾個較為簡單的範例搭配 async
和 await
再重新認識一遍!
假設我們需要依序執行 5個函式, 並且這5個都需要等待一秒鐘,我們的程式碼就會寫的像下面這樣的 Callback Hell:
const callbackHellRun =
(do_something_here: {(time: string): void;}) => {
setTimeout(() => {
do_something_here('1秒');
setTimeout(() => {
do_something_here('2秒');
setTimeout(() => {
do_something_here('3秒');
setTimeout(() => {
do_something_here('4秒');
setTimeout(() => {
do_something_here('5秒');
}, 1000);
}, 1000);
}, 1000);
}, 1000);
}, 1000);
}
callbackHellRun((time: string) => console.log(`Callback Hell: ${time}`));
這時候為了避免 callback hell,我們將setTimeout
的部份改成 Promise
的寫法:
const delay = (second: number) =>
new Promise(resolve => setTimeout(resolve, second));
由於 Promise
是屬於非同步的, 為了讓他一個接著一個執行,並且我們不要使用 callback 的方式,我們會需要使用 async
讓他知道我們這個函式裡面所執行的有包含非同步的呼叫,並且,在非同步呼叫前面加上 await
告知要等他執行完才能繼續往下。
舉例來說,如果我們這樣寫,他的輸出結果 1秒, 2秒, 3秒, 4秒, 5秒
這五個會同時出現,並且只會花一秒鐘的時間就完成。
const runAsync = (do_something: {(time: string): void}) => {
delay(1000);
do_something('1秒');
delay(1000);
do_something('2秒');
delay(1000);
do_something('3秒');
delay(1000);
do_something('4秒');
delay(1000);
do_something('5秒');
}
runAsync((time: string) => console.log(time));
但如果我們有使用 async
以及 await
,他的輸出結果就會是一次輸出一個, 並且依照 1秒, 2秒, 3秒, 4秒, 5秒
的順序一個接著一個,總共花五秒鐘完成。
const runAsync = async (do_something: {(time: string): void}) => {
await delay(1000);
do_something('1秒');
await delay(1000);
do_something('2秒');
await delay(1000);
do_something('3秒');
await delay(1000);
do_something('4秒');
await delay(1000);
do_something('5秒');
}
runAsync((time: string) => console.log(time));
還記得昨天有提到,一個 Promise
可能的結果會是成功的 resolve
, 也可能是失敗的 reject
。並且,在 async
的 function 中,也有可能包含同步或非同步的 function,這些我們全部都可以使用 await
來等他,雖然同步的 function 是不需要使用 await
的,但是,用了也不會怎麼樣。
// 這一行是為了範例使用的,因為我們有一個 Promise 只丟出一個 Error
// 一般來說這樣寫是會有問題的
process.on('unhandledRejection', () => null);
const notAPromise = 123;
const promiseThatWillResolve = new Promise(resolve => {
setTimeout(() => {
resolve(456);
}, 1000);
});
const promiseThatWillReject = new Promise((res, reject) => {
setTimeout(() => {
reject(new Error('哎呀!發生錯誤了!我是錯誤訊息!'));
}, 1000);
});
async function demoAsyncFunction() {
// 這裡其用不用 await 都沒差
const res1 = await notAPromise;
console.log({forNotAPromise: res1});
const res2 = await promiseThatWillResolve;
console.log({forPromiseThatWillResolve: res2});
try {
// 這裡會丟出一個錯誤, 因為他的結果是 Reject
const res3 = await promiseThatWillReject;
console.log('在這個範例中,這行遠遠不會被執行到');
} catch (e) {
console.log({forPromiseThatWillReject: e.message});
}
}
demoAsyncFunction();
上面那個範例的輸出結果就會是:
{ forNotAPromise: 123 }
{ forPromiseThatWillResolve: 456 }
{ forPromiseThatWillReject: '哎呀!發生錯誤了!我是錯誤訊息!' }