1.1 非同期性の基本概念
JavaScriptの非同期性は、メインスレッドをブロックせずにバックグラウンドでタスクを実行することを可能にします。 ネットワークリクエストやファイルの読み取り、タイマーのような時間がかかるかもしれないタスクに特に重要です。 ここでは、JavaScriptの非同期プログラミングの基本的な概念を紹介し、その使用例を示します。
JavaScriptのシングルスレッド特性
JavaScriptはシングルスレッド言語です。つまり、一つのスレッドでコードを順次実行します。 しかし、非同期操作により、バックグラウンドでタスクを実行し、メインスレッドを他のタスクに利用可能にします。
Event Loop (イベントループ)
イベントループは、JavaScriptが非同期タスクを処理するための重要なメカニズムです。 イベントループはメッセージキュー(Message Queue)とマイクロタスクキュー(Microtask Queue)を管理し、 非同期操作の実行を保証します。
- メッセージキュー: イベントハンドラーやネットワークリクエスト、タイマーなどのタスクを含みます。このキューのタスクは順次実行されます。
- マイクロタスクキュー: メッセージキュー内のタスクよりも高い優先度を持つタスクを含みます。例としては、Promiseの完了やコールバックの呼び出しなどがあります。
イベントループは両方のキューを常にチェックし、メインスレッドが空いたときにタスクを実行します。
非同期操作
非同期操作はバックグラウンドでタスクを実行することを可能にします。主な非同期操作の例には以下があります:
- タイマー (
setTimeout
,setInterval
) - イベントハンドラー
- ネットワークリクエスト (例:
XMLHttpRequest
,Fetch API
) - ファイルの読み書き (Node.jsで)
非同期操作のいくつかの例を見ていきましょう。
1.2 タイマー
タイマーは、遅延や定期的な間隔でタスクを実行することを可能にします。
setTimeoutの使用例
この例では、setTimeout
が2秒後に関数を実行するように設定されています。結果として、Start
とEnd
が最初に表示され、 その後2秒後にExecuted after 2 seconds
が表示されます。
console.log('Start');
setTimeout(() => {
console.log('Executed after 2 seconds');
}, 2000);
console.log('End');
setIntervalの使用例
この例では、setInterval
が関数を1秒ごとに実行し、カウンタを増加させてその値を出力します。 カウンタが5に達すると、clearInterval
を使ってインターバルが解除されます:
let counter = 0;
const intervalID = setInterval(() => {
counter++;
console.log(`Counter: ${counter}`);
if (counter >= 5) {
clearInterval(intervalID);
}
}, 1000);
1.3 イベントハンドラー
イベントハンドラーは、ユーザーの操作やその他のイベントに応答してコードを実行します。
イベントハンドラーの使用例
この例では、click
イベントハンドラーがボタンに追加されており、ユーザーがボタンをクリックすると Button clicked!
というメッセージが表示されます:
<!DOCTYPE html>
<html>
<head>
<title>Event Handler Example</title>
</head>
<body>
<button id="myButton">Click me</button>
<script>
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked!');
});
</script>
</body>
</html>
1.4 ネットワークリクエスト
ネットワークリクエストは、サーバーへの非同期HTTPリクエストを実行することを可能にします。
XMLHttpRequestの使用例
この例では、APIへの非同期GETリクエストを作成し、リクエストが完了すると、レスポンスをコンソールに出力します:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
const response = JSON.parse(xhr.responseText);
console.log(response);
}
};
xhr.send();
1.5 イベントループの動作
イベントループの動作をよりよく理解するために、次の例を見てみましょう:
console.log('Start');
setTimeout(() => {
console.log('Timeout 1');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 1');
});
setTimeout(() => {
console.log('Timeout 2');
}, 0);
Promise.resolve().then(() => {
console.log('Promise 2');
});
console.log('End');
予想される出力は以下のとおりです:
Start
End
Promise 1
Promise 2
Timeout 1
Timeout 2
この例では、まず同期操作が実行されます (console.log('Start')
および console.log('End')
)。次に マイクロタスク (Promiseハンドラー) が実行され、その後でメッセージキューのタスク (setTimeout
) が実行されます。
GO TO FULL VERSION