WebシステムにおけるHTTP通信は非同期処理で行われることが一般的です。非同期処理とは、ある処理の完了を待たずに次の処理を実行できることを指します。この方式を採用することで、ユーザーの操作に対する応答性を高めることができます。
具体例を交えて非同期処理の流れを説明します。
例1) JavaScriptにおけるAjax通信
// XMLHttpRequestオブジェクトを生成
const xhr = new XMLHttpRequest();
// リクエストを初期化
xhr.open('GET', '/api/data', true);
// レスポンスが返された際のコールバック関数を設定
xhr.onload = function() {
if (xhr.status === 200) {
// レスポンスの処理
console.log(xhr.response);
} else {
// エラー処理
console.error('Request failed: ' + xhr.statusText);
}
}
// リクエストを送信
xhr.send();
// 非同期処理のため、ここで次の処理が実行される
console.log('Request sent!');
上記の例では、XMLHttpRequestオブジェクトを使ってサーバーにGETリクエストを送信しています。send()メソッドを呼び出した時点で、リクエストはバックグラウンドで非同期に実行されます。そのため、最後の’Request sent!’がコンソールに出力された後、レスポンスが返されるのを待つことなく次の処理に進みます。
レスポンスが返された際には、onloadイベントが発火し、設定したコールバック関数が実行されます。この関数内で、レスポンスの処理を行っています。
例2) Node.jsにおけるHTTP通信
Node.jsではコールバック関数と非推奨のPromiseの他に、async/awaitを使った非同期処理が可能です。
const https = require('https');
async function fetchData() {
return new Promise((resolve, reject) => {
https.get('https://api.example.com/data', (res) => {
let data = '';
// レスポンスが返される度に実行される
res.on('data', (chunk) => {
data += chunk;
});
// レスポンスの終了時に実行される
res.on('end', () => {
resolve(JSON.parse(data));
});
}).on('error', (err) => {
reject(err);
});
});
}
async function processData() {
try {
const data = await fetchData();
console.log(data);
} catch(err) {
console.error(err);
}
}
processData();
console.log('Request sent!');
fetchData関数はhttps.getメソッドを使って外部APIからデータを取得する非同期処理を行っています。fetchDataからのレスポンスは、Promiseを介して処理されます。
processData関数はasync/awaitを使って、fetchDataからのデータ取得を非同期に実行しています。await fetchData()の行で、フェッチが完了するまでブロックされますが、その間に次の行である’Request sent!’がコンソールに出力されます。
フェッチが完了すると、データがdataに代入され、それを処理することができます。
このように、HTTPの非同期処理を使うことで、ブラウザやNode.jsアプリケーションの応答性を高められ、ユーザービリティの向上につながります。ただし、コールバック地獄と呼ばれる複雑なコールバックのネストを避けるため、Promiseやasync/awaitなどの制御フローを工夫する必要があります。