JavaScriptの非同期処理について図を使って説明してみる
こんにちは、Kosukeeeです。
現在チャットアプリのチュートリアルを準備しているのですが、そこで非同期処理の一連の流れがあったので今回のトピックとして取り上げてみようと思います。
ここでは実際のウェブアプリでの使用例と合わせて解説することでイメージしやすくなるように説明していきたいと思います。
非同期処理の実際の使用例
現在作っているチャットアプリではテキスト以外にも画像のファイルデータが送れます。
ここでのフローを詳細に説明すると
1:画像を選択して「アップロード」ボタンをクリックする
2:画像がサーバーにアップロードされる(進捗状況をプログレスバーで表示)
3:アップロードされた画像のURLを受け取ってチャットアプリのタイムライン上に画像を表示する
2の「画像がサーバーにアップロードされる」という処理が終わってから3の「アップロードされた画像のURLを受け取る」という流れになるので2番目の処理が終わるのを待つ必要があります。
なのでここを非同期処理にする必要があります。
「ファイルをアップロードする」をクリックするとモーダルが表示されます。
そして画像を選択して「送る」をクリックするとファイルがサーバーにアップロードされます。
そしてファイルのアップロードが終わるとその画像のURLを取得してチャットアプリのタイムライン上に表示されます。
タイムラインに表示するためには、データベースにファイルがアップロードされるのを待って画像のURLを取得する必要があります。
非同期処理の簡単なおさらい
まず非同期処理を理解するためには同期処理というものを理解する必要があります。
同期処理というのは上から順番にプログラムを実行・処理していくことを言います。言い換えると先にあるコードの実行・処理が完了しない限り次のプログラムの実行が始まりません。
ここで問題となるのが処理に時間がかかるようなプログラムがある場合です。この処理が完了するまで何もできないという状態(フリーズ)になってしまいます。
そこで非同期処理の出番になります。
JavaScriptではsetTimeoutなどの関数がよく引き合いに出されますね。
非同期処理では一つ一つの処理を実行して完了するまで待つのではなく、実行しつつ次の処理に移ります。
なので時間のかかるプログラムを実行している間でも次のプログラムの実行を開始することができます。
JavaScriptは(基本的には)シングルスレッドの言語
JavaScriptは基本的にシングルスレッドのプログラミング言語です。
すなわちスレッドが一つしかないので全ての処理はこのスレッドで行う必要があります。
このスレッドはメインスレッドと呼ばれています。
このメインスレッドはブラウザの表示更新などのUIにも使われているため、このスレッドが何かの処理でいっぱいになっていると表示が更新されなくなる(フリーズ状態)などの問題が発生してしまいます。
そのためデータの取得などの時間がかかる処理をする場合は対処する必要があります。
この問題に対処するために非同期処理があります。
プログラムを書いていると「この処理が終わったらその結果を受け取って次の処理を開始する」という流れで書く必要が出てきます。
これを可能にするのが「イベントループ」という概念です。
コールバック/Promise/Async/Await
以前であればその処理のためにコールバックが使用されていました。
ただしこのコールバックはネストが深くなってしまいコードが読みにくくなるという問題がありました(コールバック地獄と呼ばれています)。
このコールバック地獄回避のためにPromiseというオブジェクトが用意されています。
Promiseでは非同期処理に成功した時の処理をコールバック関数としてthenメソッドへ渡し、失敗した時の処理をcatchメソッドへ渡します。
Promiseを使用することでネストの階層が深くなるのを防ぐことができるので読みやすいコードに置き換えられるようになります。
例えば「画像をアップロードした」後に「画像のURLを取得してチャットのタイムラインに画像を表示する」というコードを書く場合「.then()」で繋いでいく必要があります。
これでも充分にシンプルなのですが、この非同期の処理が増えてくるとやはり読みにくさが出てきてしまいます。
そこでこのPromiseのコードを読みやすくしたのがAsync/Awaitという構文です。
例えば先ほどのコードでいうと「.then()」でコールバック関数を使用する代わりにawaitで結果を待って変数に代入します。
awaitを使用した行では処理が終わるまでは次の行に移動しないため、同期的に書けるようになり読みやすくなります。
ちなみにAsync/Awaitは構文であって、Promiseはビルトインオブジェクトです。
Async/Awaitは実際はその裏ではPromiseを使用しています。
これで説明は以上になります。
また今回は触れませんでしたが、JavaScriptにはWeb WorkersというAPIがありメインスレッド以外でJavaScriptを実行できます。
なので厳密にはJavaScriptはマルチスレッドでも実行可能です。
ただ今回の範疇から外れるため外しています。
また別のノートにて取り上げてみたいと思います。
最後までお読みいただきありがとうございました。