目的
今回、初めてJavaScriptの非同期処理を使用してコーディングする機会があり、その中でよく見かける「Promise」と「async/await」について、初学者が一番初めに悩む処理順序について、少しでも理解できるように自身が学んだ内容を記載します。
非同期とは
まずは「同期」処理を交えて考えてみましょう。
同期処理とは、コードを書いた順に上から下まで順番に処理をします。非同期処理とは、ある処理が完了するまでに時間がかかった場合、その処理の完了を待たずに別の処理を実行します。
データの取得(データベースアクセス)、画像の読込みなどの時間を要する処理に非同期処理を利用すると、利用者は処理完了(画面フリーズ)を待たずに、アプリケーションの操作が可能となります。
非同期処理がないと、時間がかかる処理の場合、そこで処理が止まってしまい、リソースの非効率となります。それを防ぐために非同期処理を利用します。
同期処理の例)
処理Bに1時間かかるとすると、処理Cは処理Bの完了を1時間待ってから実行する
・処理A → 処理B → 1時間待つ → 処理C
Promiseで非同期処理を書く
非同期処理をメソッドチェーンで記載できるようになるので、非同期処理の可読性が向上します。
※Promise以前の非同期処理の書き方は「コールバック ネスト」などで検索すれば確認できますが涙目になります。
<サンプルコード>
function promiseTest() { return new Promise((resolve, reject) => { let isSuccess = true; // 何かの処理結果。サンプルとして成功(true)としている。 // 成功時 if (isSuccess) { resolve("処理成功"); // 失敗時 } else { reject(new Error("処理失敗")); } }); } // 処理A(非同期処理) promiseTest().then((value) => { // 成功時 console.log(value); // 2番目 }).catch((error) => { // 失敗時 console.error(error); }).finally(() => { // 成功、失敗に関わらず必ず実行 console.log("処理A"); // 3番目 }); // 処理B console.log("処理B"); // 1番目
処理Aが先に実行されると思いきや処理Aは非同期処理なので、処理Bが先に実行されます。
async/awaitで非同期処理を書く
同期処理に近い形でコードを書けるようになります。try catch構文も同期処理の時と同じように書けます。そのためPromiseよりも可読性が上がります。
awaitをつけると上から下へと順番に処理を進めます。つまり、同期処理と同じ流れで処理が進んでいきます。非同期処理は処理順序を追いかけるのが非常に難しいですがが、処理順序を意識しなくてもよくなるので直感的に理解できるようになります。
※「await」は必ず「async」とセットで使用します。
<サンプルコード>
async function promiseTest() { return new Promise((resolve, reject) => { let isSuccess = true; // 何かの処理結果。サンプルとして成功(true)としている。 // 成功時 if (isSuccess) { resolve("処理成功"); // 失敗時 } else { reject(new Error("処理失敗")); } }); } try { let result = await promiseTest(); console.log(result); // 成功時 } catch(error) { console.error(error); // 失敗時 } finally { // 処理A(非同期処理) console.log("処理A"); // 1番目 } // 処理B console.log("処理B"); // 2番目
※注意点
「await」キーワードがあるおかげで、それ以降の非同期処理(処理A)は同期処理(処理B)の後に実行されず、処理A→処理Bと上から順番に実行されます(Promiseのときは同期処理の後に非同期処理が実行されていた)。なお、「async/await」はPromise以降に追加された機能なので、使用できるブラウザのバージョンを確認してください。
参考
「async/await」が使えればいいでしょ!と「async/await」から手を付けても分からないので(私の場合は)ちゃんと順番で知識を積み上げましょう。
下記、参考サイトは非常にお世話になっております。ありがとうございます。
【イベントループとプロミスチェーンで学ぶJavaScriptの非同期処理】
【JavaScript Promiseの本】
※上記サイトからこちらへ誘導されます。ブラウザ内の説明コード内でJavaScriptを実行できるので写経し易いです。
まとめ
非同期処理について、最初から理解できなかったです(現在もかろうじて読み進められるかなといった感じです)。その理由としては処理順序が理解できていなかったからです。まずは、どの順序で動作するのかという点に着目し、読めるようになることを目標に学習を進めていけばいいと思います。
実際に非同期処理を1から書いていくことは難しいです。どの部分を非同期にする必要があるのかといった設計を考える作業や複数の非同期処理を実行させる場合、スレッドを占有しないようにするにはどうすればいいのか、そもそもアロー関数を理解していないと(アロー関数内でのthisなど)読み進めないなどヤクの毛刈りがものすごく発生するので、理解するまでかなりの時間を要します。
サンプルで記載した「Promise」、「async/await」を理解していると「読む」ことはできると思うので、読むことから始めて知識を積み上げていけばいいと思います。