JavaScript Promise: 終了待ちの完全ガイド

JavaScriptにおける非同期処理と同期処理

JavaScriptはシングルスレッドの言語であり、一度に一つのタスクしか処理できません。しかし、非同期処理を利用することで、時間のかかるタスクをバックグラウンドで実行し、その完了を待つことなく他のタスクを進めることができます。これにより、ウェブページがフリーズすることなく、ユーザーに快適な体験を提供することが可能になります。

同期処理

同期処理は、コードが上から下へと一行ずつ順番に実行され、一つのタスクが完了するまで次のタスクは開始されません。これは、コードの読みやすさや理解しやすさに寄与しますが、時間のかかるタスク(例えば、大量のデータをフェッチするネットワークリクエスト)がある場合、そのタスクが完了するまで他のタスクがブロックされてしまいます。

console.log('Start');
let result = database.query('SELECT * FROM huge_table'); // 時間がかかるタスク
console.log('Result', result);
console.log('End');

上記のコードでは、データベースクエリが完了するまで、その後のconsole.log('End')は実行されません。

非同期処理

一方、非同期処理では、時間のかかるタスクをバックグラウンドで実行し、そのタスクが完了したときに何をすべきかを指示するコールバック関数を登録します。これにより、時間のかかるタスクが完了するのを待つことなく、他のタスクをすぐに実行することができます。

console.log('Start');
database.query('SELECT * FROM huge_table', function(result) {
  console.log('Result', result);
});
console.log('End');

このコードでは、データベースクエリがバックグラウンドで実行され、その結果を処理するコールバック関数が登録されます。そのため、console.log('End')はすぐに実行され、ユーザーはフリーズすることなく他の操作を続けることができます。

JavaScriptの非同期処理は、コールバック関数だけでなく、Promiseやasync/awaitといった機能を利用してより直感的に、または効率的に書くことができます。これらの詳細については、次のセクションで説明します。

非同期処理の完了を待つ方法1|promiseを使う

JavaScriptのPromiseは、非同期処理の結果を表現するためのオブジェクトです。Promiseは、非同期処理が成功した場合と失敗した場合の2つの結果を持つことができます。これらはそれぞれ「resolve」(解決)と「reject」(拒否)と呼ばれます。

Promiseを作成するには、new Promise()コンストラクタを使用します。このコンストラクタは、引数として実行関数を取ります。実行関数は、2つの引数、resolverejectを取ります。

let promise = new Promise((resolve, reject) => {
  // 非同期処理
});

非同期処理が成功した場合はresolveを、失敗した場合はrejectを呼び出します。これらの関数は、それぞれPromiseの「解決値」または「拒否理由」を引数として取ります。

let promise = new Promise((resolve, reject) => {
  let success = true; // 非同期処理の結果を模擬
  if (success) {
    resolve('成功!');
  } else {
    reject('失敗...');
  }
});

Promiseの状態は、作成時には「pending」(未決)で、resolveまたはrejectが呼び出されると「fulfilled」(解決済み)または「rejected」(拒否済み)になります。

Promiseの結果を取得するには、.then()メソッドを使用します。このメソッドは、Promiseが解決したときに呼び出されるコールバック関数を登録します。また、.catch()メソッドを使用して、Promiseが拒否されたときに呼び出されるコールバック関数を登録することもできます。

promise
  .then(result => {
    console.log(result); // '成功!'
  })
  .catch(error => {
    console.error(error); // '失敗...'
  });

このように、Promiseを使用すると、非同期処理の完了を待つことができます。また、Promiseはチェーン可能であり、複数の非同期処理を順番に実行することも可能です。これについては、次のセクションで詳しく説明します。

非同期処理の完了を待つ方法2|async/awaitを使う

JavaScriptのasyncawaitは、非同期処理をより直感的に書くための構文です。これらを使用すると、非同期処理をあたかも同期処理のように書くことができます。

asyncは関数の前に置くキーワードで、その関数が必ずPromiseを返すことを示します。awaitは非同期処理の結果を待つためのキーワードで、async関数の中でのみ使用できます。

以下に、asyncawaitを使用した非同期処理の例を示します。

async function fetchAndLog() {
  let response = await fetch('https://api.example.com/data'); // 非同期処理
  let data = await response.json(); // 非同期処理
  console.log(data);
}

fetchAndLog();

このコードでは、fetchAndLog関数はasyncキーワードにより非同期関数となり、Promiseを返します。fetch関数とresponse.jsonメソッドは非同期処理を行うため、その結果を待つにはawaitキーワードを使用します。

awaitキーワードにより、非同期処理の結果が得られるまで次の行の実行を一時停止します。しかし、これはそのasync関数の中だけであり、他のタスクがブロックされることはありません。

asyncawaitを使用すると、非同期処理を同期処理のように直列的に書くことができます。これにより、コードが読みやすくなり、エラーハンドリングも容易になります。ただし、これらのキーワードはPromiseに基づいているため、Promiseの動作を理解することが重要です。これについては、次のセクションで詳しく説明します。

Promiseの状態とその扱い方

JavaScriptのPromiseは、非同期処理の結果を表現するためのオブジェクトで、以下の3つの状態を持つことができます。

  1. pending(未決): 初期状態で、非同期処理がまだ完了していない状態を指します。
  2. fulfilled(解決済み): 非同期処理が成功し、Promiseが結果を持つ状態を指します。
  3. rejected(拒否済み): 非同期処理が失敗し、Promiseがエラーを持つ状態を指します。

Promiseは、これらの状態を一度だけ変更できます。つまり、一度fulfilledまたはrejectedになったPromiseの状態は、それ以降変更することはできません。

Promiseの状態に基づいて処理を行うためには、.then().catch().finally()といったメソッドを使用します。

  • .then()メソッドは、Promiseがfulfilledになったときに実行するコールバック関数を登録します。このメソッドは新しいPromiseを返し、そのPromiseは元のPromiseの結果に基づいてfulfilledまたはrejectedになります。
let promise = Promise.resolve('成功!'); // 解決済みのPromiseを作成

promise.then(result => {
  console.log(result); // '成功!'
});
  • .catch()メソッドは、Promiseがrejectedになったときに実行するコールバック関数を登録します。このメソッドも新しいPromiseを返します。
let promise = Promise.reject('失敗...'); // 拒否済みのPromiseを作成

promise.catch(error => {
  console.error(error); // '失敗...'
});
  • .finally()メソッドは、Promiseがfulfilledでもrejectedでも実行するコールバック関数を登録します。このメソッドは新しいPromiseを返し、そのPromiseは元のPromiseと同じ状態になります。
let promise = Promise.resolve('成功!'); // 解決済みのPromiseを作成

promise.finally(() => {
  console.log('完了'); // '完了'
});

これらのメソッドを使用することで、Promiseの状態に基づいて適切な処理を行うことができます。また、これらのメソッドはチェーン可能であり、複数の非同期処理を順番に実行することも可能です。これについては、次のセクションで詳しく説明します。

非同期処理の完了を待つ具体的なコード例

以下に、JavaScriptのPromiseとasync/awaitを使用した非同期処理の完了を待つ具体的なコード例を示します。

Promiseを使用した例

// 非同期処理を模擬する関数
function asyncTask() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('タスク完了!');
    }, 1000);
  });
}

// 非同期処理の完了を待つ
asyncTask()
  .then(result => {
    console.log(result); // 'タスク完了!'
  })
  .catch(error => {
    console.error(error);
  });

このコードでは、asyncTask関数は非同期処理を模擬し、1秒後にPromiseを解決します。.then()メソッドを使用して、非同期処理の結果を待ち、その結果をログに出力します。

async/awaitを使用した例

// 非同期処理を模擬する関数
function asyncTask() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('タスク完了!');
    }, 1000);
  });
}

// 非同期処理の完了を待つ
async function waitForTask() {
  try {
    let result = await asyncTask();
    console.log(result); // 'タスク完了!'
  } catch (error) {
    console.error(error);
  }
}

waitForTask();

このコードでは、asyncTask関数は非同期処理を模擬し、1秒後にPromiseを解決します。waitForTask関数はasync関数で、awaitキーワードを使用して非同期処理の結果を待ち、その結果をログに出力します。エラーハンドリングはtry/catchブロックを使用して行います。

これらのコード例は、JavaScriptの非同期処理の完了を待つ基本的な方法を示しています。非同期処理はJavaScriptの重要な特性であり、これらの概念を理解することは、効率的なコードを書くために重要です。次のセクションでは、Promiseとasync/awaitの違いについて詳しく説明します。

Promiseとasync/awaitの違いとは?

JavaScriptの非同期処理を扱うための2つの主要な概念、Promiseとasync/awaitには、以下のような違いがあります。

Promise

  • Promiseは、非同期処理の結果を表現するオブジェクトです。
  • Promiseは、非同期処理が成功した場合(fulfilled)と失敗した場合(rejected)の2つの状態を持つことができます。
  • Promiseの結果を取得するためには、.then()メソッドを使用します。また、エラーハンドリングには.catch()メソッドを使用します。
  • Promiseはチェーン可能であり、複数の非同期処理を順番に実行することができます。
fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

async/await

  • async/awaitは、非同期処理をより直感的に書くための構文です。
  • asyncキーワードを関数の前に置くと、その関数は必ずPromiseを返します。
  • awaitキーワードを非同期処理の前に置くと、その非同期処理の結果が得られるまで次の行の実行を一時停止します。
  • async/awaitを使用すると、非同期処理を同期処理のように直列的に書くことができます。これにより、コードが読みやすくなり、エラーハンドリングも容易になります。
async function fetchData() {
  try {
    let response = await fetch('https://api.example.com/data');
    let data = await response.json();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

fetchData();

これらの違いを理解することで、非同期処理を効果的に扱うことができます。次のセクションでは、JavaScript Promiseのベストプラクティスについて詳しく説明します。

JavaScript Promiseのベストプラクティス

JavaScriptのPromiseは非同期処理を扱うための強力なツールですが、その力を最大限に引き出すためには、以下のようなベストプラクティスを守ることが重要です。

1. エラーハンドリングを忘れない

Promiseがrejectedになったときには、適切なエラーハンドリングを行うことが重要です。.catch()メソッドを使用して、Promiseが拒否されたときに呼び出されるコールバック関数を登録します。

fetch('https://api.example.com/data')
  .then(response => response.json())
  .catch(error => console.error('エラー:', error));

2. Promiseチェーンを利用する

Promiseはチェーン可能であり、複数の非同期処理を順番に実行することができます。これにより、コードが読みやすくなり、非同期処理の流れを一目で理解することができます。

fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('エラー:', error));

3. async/awaitを活用する

asyncawaitを使用すると、非同期処理を同期処理のように直列的に書くことができます。これにより、コードが読みやすくなり、エラーハンドリングも容易になります。

async function fetchData() {
  try {
    let response = await fetch('https://api.example.com/data');
    let data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('エラー:', error);
  }
}

fetchData();

4. Promise.allを使う

複数の非同期処理を並行して実行し、すべての処理が完了するのを待つ場合には、Promise.allを使用します。

let promise1 = fetch('https://api.example.com/data1').then(response => response.json());
let promise2 = fetch('https://api.example.com/data2').then(response => response.json());

Promise.all([promise1, promise2])
  .then(([data1, data2]) => {
    console.log(data1, data2);
  })
  .catch(error => console.error('エラー:', error));

これらのベストプラクティスを守ることで、JavaScriptのPromiseを効果的に使用し、非同期処理をより効率的に扱うことができます。次のセクションでは、JavaScript Promiseの詳細な使い方について詳しく説明します。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール