JavaScriptにおけるPromiseクラス

JavaScriptにおけるPromiseクラス

この記事ではJavaScriptにおけるPromiseクラスについて説明します。

YouTube Video

Promise

Promiseクラスは、非同期処理を扱うためのクラスです。処理が成功した場合の結果や、失敗した場合のエラーハンドリングを行います。非同期の処理が完了するまで待たないといけない場合には、コールバック関数を使うことが一般的でしたが、Promiseはそれをより分かりやすく、強力にしたものです。

1const promise = new Promise((resolve, reject) => {
2    setTimeout(() => resolve("Done!"), 1000);
3});
4
5// Displays "Done!" after 1 second
6promise.then(result => console.log(result));
  • このコードは、1秒後に "Done!" と表示する非同期処理を実行する例です。
    • 最初に、new Promiseによって新しくPromiseオブジェクトを作成しています。 引数には、成功時に呼ばれるresolveと失敗時に呼ばれるrejectの2つのコールバックを持つ関数を渡します。
    • setTimeout を使って、1秒後に resolve() を呼び出しています。
    • promiseオブジェクトのthen()メソッドによって、処理の完了を待ち、結果を表示しています。

基本的な構造

Promiseは、最終的に成功失敗の2つの結果を持つオブジェクトです。

 1const promise = new Promise((resolve, reject) => {
 2    // Asynchronous operation
 3    // Flag indicating whether the operation was successful
 4    const success = true;
 5
 6    if (success) {
 7        resolve('Operation successful!');
 8    } else {
 9        reject('An error occurred');
10    }
11});
  • 成功の場合には、resolve()を呼び出します。
  • 失敗の場合には、reject()を呼び出します。

Promiseオブジェクトは次の3つの状態を持っています。

1promise
2    .then((result) => {
3        console.log(result);
4    })
5    .catch((error) => {
6        console.error(error);
7    })
  • Pending(待機中)
    • 非同期処理がまだ完了していない状態です。
  • Fulfilled(成功)
    • 非同期処理が成功し、resolve()によって結果が返された状態です。then()メソッドによって結果を受け取ります。
  • Rejected(失敗)
    • 非同期処理が失敗し、reject()によってエラーが発生した状態です。catch()メソッドによってエラーを受け取ります。

then()catch()メソッド

Promiseを使うと、非同期処理が完了したときに行う処理を定義できます。これには、then()catch()メソッドを使います。

then()

1const promise = new Promise((resolve, reject) => {
2    resolve('Operation successful!');
3});
4
5promise.then((result) => {
6    console.log(result);  // "Operation successful!"
7});
  • then()メソッドは、Promiseが成功した場合に呼ばれる関数を指定します。

catch()

1const promise = new Promise((resolve, reject) => {
2    reject('An error occurred');
3});
4
5promise.catch((error) => {
6    console.error(error);  // "An error occurred"
7});
  • catch()メソッドは、Promiseが失敗した場合に呼ばれる関数を指定します。

finally()メソッド

 1const promise = new Promise((resolve, reject) => {
 2    resolve('Operation successful!');
 3});
 4
 5promise
 6    .then((result) => {
 7        console.log(result);
 8    })
 9    .catch((error) => {
10        console.error(error);
11    })
12    .finally(() => {
13        console.log('The operation has completed');
14    });
  • finally()メソッドは、Promiseが成功または失敗のいずれにしても、最終的に必ず実行されるコードを定義します。

then()チェーン

then()は新しいPromiseを返すので、次のthen()チェーンできます。

 1const promise = new Promise((resolve, reject) => {
 2    setTimeout(() => {
 3        resolve(1);
 4    }, 1000);
 5});
 6
 7promise
 8    .then(result => {
 9        console.log(result); // 1
10        return result + 1;
11    })
12    .then(result => {
13        console.log(result); // 2
14        return result + 1;
15    })
16    .then(result => {
17        console.log(result); // 3
18    })
19    .catch(error => {
20        console.error(error.message); // Something went wrong
21    });
  • このコードでは、最初のresolve()で1が渡され、各thenで返した値は、次のthenに引き継がれます。
  • catch()を使うと、どこかのチェーンでエラーが発生したときにまとめて処理できます。

実際の例

例えば、サーバーからデータを取得するためにPromiseを使うことがよくあります。fetch() APIを使った例を見てみましょう。

 1fetch('https://codesparklab.com/json/example.json')
 2    .then(response => {
 3        if (!response.ok) {
 4            throw new Error('Network error');
 5        }
 6        return response.json();
 7    })
 8    .then(data => {
 9        console.log(data);
10    })
11    .catch(error => {
12        console.error('Error:', error);
13    });
  • このコードでは、fetch()Promiseを返すので、サーバーからのレスポンスを受け取った後にデータを処理するためにthen()を使っています。エラーが発生した場合はcatch()で処理します。

複数のPromiseを扱う

Promise.all()

複数のPromiseを同時に実行し、それぞれが成功した場合のみ次の処理を行う場合、Promise.all()を使います。

 1const promise1 = Promise.resolve(1);
 2const promise2 = Promise.resolve(2);
 3const promise3 = Promise.resolve(3);
 4
 5Promise.all([promise1, promise2, promise3])
 6    .then((results) => {
 7        console.log(results);  // [1, 2, 3]
 8    })
 9    .catch((error) => {
10        console.error('Error :', error);
11    });
  • 全てのPromiseが成功した場合のみthen()が呼ばれます。1つでも失敗すると、catch()が呼ばれます。

Promise.allSettled()

複数の Promise を同時に実行し、それぞれの成否に関係なくすべての結果を取得したい場合、Promise.allSettled() を使います。

 1const promise1 = Promise.resolve(1);
 2const promise2 = Promise.reject("Failed");
 3const promise3 = Promise.resolve(3);
 4
 5Promise.allSettled([promise1, promise2, promise3])
 6    .then((results) => {
 7        results.forEach(result => console.log(result));
 8        // [
 9        //   { status: 'fulfilled', value: 1 },
10        //   { status: 'rejected', reason: 'Failed' },
11        //   { status: 'fulfilled', value: 3 }
12        // ]
13    });
  • すべての Promise が完了(成功または失敗)した時点で then() が呼ばれます。各結果には status プロパティ('fulfilled' または 'rejected')が含まれます。失敗しても他の処理には影響しません。

Promise.race()

Promise.race()は、最も早く解決された、つまり成功または失敗したPromiseの結果を取得します。

1const promise1 = new Promise((resolve) => setTimeout(resolve, 100, 'First'));
2const promise2 = new Promise((resolve) => setTimeout(resolve, 500, 'Second'));
3
4Promise.race([promise1, promise2]).then((result) => {
5    console.log(result);  // "First"
6});
  • この例のように、最初に完了したPromiseの結果が返されます。

async/awaitとの関係

async/await構文を使うことで、Promiseをより直感的に書くことができます。async関数は常にPromiseを返し、awaitPromiseが解決するまで待機します。

 1async function fetchData() {
 2    try {
 3        const response = await fetch('https://codesparklab.com/json/example.json');
 4        const data = await response.json();
 5        console.log(data);
 6    } catch (error) {
 7        console.error('Error :', error);
 8    }
 9}
10
11fetchData();

このように、async/awaitを使うと、非同期処理が同期処理のように書けるため、コードが見やすくなります。

まとめ

  • Promiseは非同期処理の成功や失敗を扱うためのオブジェクトです。
  • then()で成功時の処理、catch()でエラー時の処理を行います。
  • finally()は成功や失敗に関わらず、最後に実行されるコードを定義します。
  • Promise.all()Promise.race()を使って、複数のPromiseをまとめて扱うことができます。
  • async/awaitは、Promiseをよりシンプルに書くための構文です。

YouTubeチャンネルでは、Visual Studio Codeを用いて上記の記事を見ながら確認できます。 ぜひYouTubeチャンネルもご覧ください。

YouTube Video