本サイトの JavaScriptで一定時間待ってから処理を開始する方法 でも少し使ったのですが、JavaScript の async / await の使い方についてこちらのページにまとめておきます。
1. JavaScript の非同期処理とは?
たいていのプログラミング言語では、
foo()
という関数を実行し、それが終了したら bar()
という関数を実行するという処理を書く場合、以下のように書きます。
foo();
bar();
「何当たり前のことを行っているんだ」と思われるかもしれませんが、JavaScript は少し違います。
JavaScript の面倒臭さ
JavaScriptの場合、foo()
関数の中で、「サーバーにアクセスする」や、「ファイルにアクセスする」といった「待ち」が発生する処理があった場合、さっさと次の bar()
が実行され、foo()
内の残りの処理は後回しにされます(これが非同期という意味になります)。
「待つ」という時間が無駄にならないので、プログラム全体から見れば効率がよいという見方もできますが、「○○○という処理が終了してから□□□という処理を開始したい」というよくある処理(同期処理)を書きたい場合に、先程のコード例のように自然な書き方ができないという面倒臭さがあるのです。
コールバックの時代
では、「JavaScript で同期処理(処理を順番に実行させる)を行う」場合にどうしていたかと言うと、初期の頃は「非同期処理を含んだ関数に コールバック関数を渡して、処理の最後に実行してもらう」というやり方をしていました。
しかしこのやり方だと、コールバック関数の増加に伴いとてつもなくコードが分かりづらくなります。階層が深くなったり、エラー処理が面倒になったりいいことがありません。
Promise をそのまま使う時代
その後、ECMAScript 6 (ES6) の仕様に Promise というオブジェクトが加わりました。これを使うと同期処理を書く場合に、コールバックをなくすことができます。
とはいえ、これではまだ「分かりやすいコードが書ける」と言うには微妙でした。
async/await の登場
そして、ECMAScript 2017 (ECMA-262) という仕様で「Async function」という機能(文法)が追加されました。これが今回の主題である「async / await」のことを指しています。
async / await というのは、Promise をより簡単に使うための文法であって、新しい機能ではありません。非同期処理が前より書きやすくなりましたが、ちゃんと理解するには依然として Promise についての理解が必要です。
2. async /await の使い方
async /await の基本的なコード例は以下です。
// 非同期処理を含み Promiseを返す関数
function foo() {
return new Promise((resolve, reject) => {
// 非同期処理(後述)
// 処理終了箇所で resolve() を実行する、エラーなら reject() を実行する
});
}
async function main() {
try {
await foo(); // 処理が終わるまで待ちます
bar();
} catch(err) {
alert(err);
}
}
main();
やっていることを以下にまとめます。
- 非同期処理を含み、Promise を返す関数を用意します。…
foo()
- async を付けた関数を用意します。…
main()
- async を付けた関数内でないと、await が使えません。
- その関数内で、await を頭につけて
foo()
を実行させます。- これで、
foo()
が終了するまで処理が次に進まなくなります。
- これで、
foo()
が終了した後で実行したい関数bar()
を記述します。
「非同期処理を含み、Promise を返す関数」というのは、例えば以下のような関数になります。
function foo() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
//setTimeout(() => {reject(new Error("エラー!"))}, 1000);
});
};
async / await の基本的な使い方は以上になります。
3. おわりに
JavaScript で「非同期処理 を 同期処理 にして使いたい」という要望があった場合、先程のコード例をベースにして考えると、意外と簡単に処理が書けるのではないでしょうか。(とはいえ、Promise
は理解していた方がよいです)
参考
- ECMAScript 2018 (ECMA-262)
- ECMAScript 2017 (ECMA-262)
- async function – JavaScript | MDN
- await – JavaScript | MDN