非同期処理とは、同期処理との違いとは
非同期処理とは、処理の終了を待たずに次の処理を行う処理のことを指します。
プログラミング言語の通常の処理では、記述されたコードが上から順番に実行されます。この時の処理の方法を同期処理と言いますが、非同期処理では、非同期で実行された処理が完了する前に他の処理も実行することができます。イメージとしては、処理の完了を待たずに同時に別の処理を行うことができるといった感じになります。
有名なサービスですと、Google Mapがそれに当たります。
ユーザーが詳しく調べたい地域をクローズアップし、システムの裏側ではその区画の店舗情報などを非同期で取得して画面上に表示する一方で、処理が完了する前でもユーザーは検索窓で検索をしたり、別の地域にクローズアップしたりすることができます。
シングルスレッドについて
単一のスレッドのことをシングルスレッドと言います。
よくJavaScriptはシングルスレッドと言われますが、これはJavaScriptのプログラムが単一のスレッドで実行されること、誤解を恐れずにいうと同時に複数の処理を実行することができないことを指します。
ここで非同期処理を使うと、同時に複数の処理を実行することができるのではないかとの疑問が出てくるかと思いますが、非同期処理は、処理自体を外部環境に依頼しその実行結果を受け取ったJavaScriptが再びシングルスレッドで処理を再開するということを行っているため、JavaScript自体が同時に複数処理を行っているわけではないと言う理解が大切です。
以下では、非同期処理が行われた際に、どのようにJavaScript内で処理を管理しているのかを確認します。
コールスタック・タスクキュー・イベントループについて
コールスタックとは、実行する処理を入れる箱のような物になります。
JavaScriptではプログラムを実行順に上から順に記述していきますが、実際にこれらを実行するにはコールスタックに入れる必要があります。
つまり、コールスタックに関数や何らかの処理が入れられて初めてそれが実行されることになります。
このコールスタックには、通常一つの処理しか入れられないため、JavaScriptはシングルスレッド・同時に複数の処理ができないとなります。
では非同期処理を行うとどうなるのか。非同期処理を行うと、その処理結果(あくまで処理画終わった後の結果になります)はタスクキューに保存されます。
タスクキューとは、JavaScriptが非同期処理を外部環境に依頼し、その結果が返ってくる箱のようなものになります。
したがって非同期処理を複数実行した場合、その結果が次々にタスクキューとして溜まっていきます。
ここでタスクキューとして蓄積されたタスクは、JavaScript内でいつ実行されるのかという疑問が出てくるかと思います。
その答えは、コールスタックが空になった時にタスクキューがあればそれが処理されます。
次にイベントループとは、コールスタックの状態監視(現在実行中か、それとも空なのか)やタスクキューの状態監視(タスクがあるのかないのか)を行い、タスクキューがあればコールスタックに追加するなどの、非同期処理を行うための一連の仕組みを指します。
非同期処理が実行される流れは以下の通りでした。
- 通常のスクリプト内で非同期処理が呼び出される(スクリプト内の処理は、コールスタックにて処理される)
- 非同期処理が外部環境にて実行される
- 非同期処理の実行結果がタスクキューに追加される
- コールスタックが空になった時点でタスクキューがコールスタックに移動され、非同期処理の結果を使ってJavaScript側の処理が行われる。
これら一連の処理が、イベントループという仕組みにより実現します。
非同期処理の種類について
JavaScriptでは大きく分けて次の3つの非同期処理が存在します。
- コールバック関数
- promise
- Async/Await
非同期処理の実装方法
コールバック関数
JavaScriptでは、コールバック関数内で非同期処理を行う関数がいくつか用意されています。
一般的なものとして以下があります。
- setTimeout:一定時間経過後に指定したコールバック関数を実行します。
- setInterval:指定した時間間隔ごとに、コールバック関数を実行します。
- fetch:ネットワークリクエストを非同期で行い、レスポンスを取得します。
//setTimeoutの構文
setTimeout(callback, delay);
//setIntervalの構文
setInterval(callback, delay);
//fetchの構文
fetch(url)
.then(response => response.json())
.then(data => {
// レスポンスデータを処理するコールバック関数
})
.catch(error => {
// エラーハンドリング用のコールバック関数
});
promise
2015年に標準化(ES2015)された機能です。
Promiseとは、非同期処理を表すオブジェクトになります。
使用方法は、以下のように行います。
- 非同期処理を行うインスタンスを作成(引数に
resolve
とreject
を指定) - 実際に行いたい非同期処理を記述
- 非同期処理に成功した場合は
resolve
を呼び出す - 失敗した場合は
reject
を呼び出す
// Promise を返す
return new Promise(function(resolve, reject) {
const a = 3;
if ( a > 1 ) {
// 成功したとき
resolve(a);
} else {
// 失敗したとき
reject(a);
}
}).then((a) =>{
console.log("1より大きい");
}).catch((a) => {
console.log("1より小さい");
})
Async/Await
後日追加予定
参考記事