Async functions
在上一篇中我們提到了 Promise ,避免使用多層 callback 所造成程式碼難以維護的問題。而 ES7 提供了 async/await 語法,可以看成是 Promise 的語法糖,更方便的寫出非同步程式碼。
async 所宣告的函式,會回傳一個 Promise ,使用方法就是在宣告的函式前增加 async 關鍵字,說明這是一個非同步的函式。
下面的範例相當於回傳一個 resolved promise:
1 2 3
| async function f() { return 1; }
|
也可以寫成這樣:
1 2 3
| async function f() { return Promise.resolve(1); }
|
Await
await 只能在 async 函式中使用,否則會拋出 syntax error 。 await 表示等待 Promise 的狀態為 resolve 或 reject 才會繼續執行函式,讓我們看一下例子:
1 2 3 4 5 6 7 8 9 10 11 12
| async function main() {
let p = new Promise((resolve, reject) => { setTimeout(() => resolve("done!"), 1000) });
let result = await p; console.log(result);
}
main();
|
範例中的程式會等待 p 一秒鐘後才會進行輸出。
下面為一個簡易的 async/await 例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function p(value) { return new Promise((resolve, reject) => { setTimeout(function() { value++ resolve(value) }, 1000) }) }
async function main() { let x1 = await p(1); let x2 = await p(2); let x3 = await 3;
console.log(x1 + x2 + x3); }
main();
|
因為 async 函式相當於回傳一個 Promise ,所以我們一樣可以用操作 Promise Chain 的方式,把 Promise 一層一層的往下傳:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| async function main() { console.log("Start main function" ); let x1 = await p1(1); let x2 = await p2(2); let x3 = await 3; await p2(4); return x1 + x2; }
main().then(value => { return value + 2 ; }).then(p1) .then((value) => { console.log(value); }).catch((error) => { console.log('error:', error) })
function p1(value) { console.log("P1 value is :" + value); return new Promise((resolve, reject) => { setTimeout(function() { value++ resolve(value) }, 1000) }) }
function p2(value) { console.log("P2 value is :" + value); return new Promise((resolve, reject) => { setTimeout(function() { value+=2 resolve(value) }, 1000) }) }
|
await 可以搭配 Promise.all 和 Promise.race 來使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| async function main() { console.log("Start main function" ); const [x1, x2] = await Promise.all([p(1000), p(2000)]); const x3 = await Promise.race([p(1000), p(2000), p(3000)]); return x1 + x2 + x3; }
main().then(value => { console.log(`value is ${value}`); })
function p(value) { return new Promise((resolve, reject) => { setTimeout(function() { if (value < 1000 ){ reject('Unexpected condition') } resolve(value) }, value) }) }
|
錯誤處理
錯誤處理的方式使用 try / catch :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const isEven = (num) => { return new Promise((resolve, reject) => { if (num % 2 == 0) { resolve('even'); } else { reject('odd'); } }); }
const verify = async (num) => { try { const sign = await isEven(num); console.log(sign); } catch (err) { console.log(err); } }
verify(8); verify(15); verify('Ian');
|
只用 catch 也行:
1 2 3 4 5 6
| const verify = async (num) => { const sign = await isEven(num); console.log(sign); }
verify('Ian').catch(err => console.log(err));
|
如果是採用以下的寫法,因為 await isEven(15) 的結果會是 reject ,所以在 x2 就會進入到 catch ,表示後面的 x3 就不會執行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const isEven = (num) => { return new Promise((resolve, reject) => { if (num % 2 == 0) { resolve('even'); } else { reject('odd'); } }); }
const verify = async () => { const x1 = await isEven(8); const x2 = await isEven(15); const x3 = await isEven('Ian'); return x1 }
verify() .then((value) => { console.log(value) }) .catch((error) => { console.log('error:', error) })
|
async/await and promise.then/catch
透過在 await 我們就可以很容易的控制非同步執行, 再搭配 try / catch 來處理例外狀況,因為在全域環境中無法使用 await ,所以這時候就可以透過 .then / catch 來控制整個流程。
參考文獻
- [JS] Async and Await in JavaScript | PJCHENder 私房菜
- JS 原力覺醒 Day16 - Async / Await:Promise 語法糖
- Day25 優雅的 Await、Async
- Async/await
- How to use async/await in JavaScript