async-awaitは、「いつ完了するか分からない処理」だけど「順番に実行したい」な事をするために使います。「コールバック地獄」と呼ばれていたような読みづらいコードをシンプルに書けます。
構文
function
の前、アロー関数なら()
の前にasync
と書きます。
async function foo() {
/* ... */
}
const bar = async () => {
/* ... */
};
そして、中でPromise
を返す関数の実行前にawait
と書けば、処理が終わるまでその場で待ってくれます。これはPromise#then
を使う方法と比べて構文を反対に書いたような形になります。つまり「関数→then
→変数」から「変数→await
→関数」といった具合です。
// Promise#then
asyncFn1().then(data => {/*...*/});
asyncFn2().then(() => {/*...*/});
// await
const data = await asyncFn1();
await asyncFn2();
例
以下は1毎にコンソールにテキストを出力する例です。
/**
* 1秒待つ
* (
* `async`と書くと`Promise`だなとわかるのでオススメしたいです
* TypeScript 除く
* )
*/
const delay = async () => new Promise(r => setTimeout(r, 1000));
(async () => {
console.log('すぐ表示');
await delay();
console.log('1秒後表示');
await delay();
console.log('さらに1秒後');
})();
エラー処理
await
文の例外はtry-catch
でキャッチすることができます。(エラーでやっているけど単に勉強の為でPromise#reject
でも良い)
class OversleepError extends Error {
constructor() {
super('寝坊した');
Error.captureStackTrace(this, OversleepError);
}
}
/**
* 寝る
*/
const sleep = async () => {
throw new OversleepError();
};
(async () => {
try {
await sleep();
} catch (err) {
console.log(err instanceof OversleepError); // true
}
})();
扱うのはPromise
なのでcatch
で一旦受け取ってできるだけ処理することももちろんできます。
/* 上の関数定義そのまま */
const eatBreakfast = async () => {
/* 食べる */
};
(async () => {
const task = {
breakfast: true
};
await sleep().catch(err => {
if (err instanceof OversleepError) {
task.breakfast = false;
return;
}
});
// 遅刻してない場合、
// 朝食を食べる
if (task.breakfast) {
await eatBreakfast();
}
})();