【イラスト付き】Promiseオブジェクト【丁寧に解説】

2024/09/05に公開

はじめに

皆さんこんにちは。
今回はPromiseオブジェクトについてご紹介します。

JavaScriptは非同期処理と切っても切り離せません。その非同期処理ではPromiseオブジェクトというものが利用されています。Promiseオブジェクトを理解することで、非同期処理の記述の本質を理解することができます。

こんな人にオススメ

  • Promiseオブジェクトについて理解したい
  • Promise対応した関数を作成したい

初めて学習する方にも分かるように、丁寧に解説していきます。
プログラミングに慣れてきた方も、是非一度目を通していただけると嬉しいです。

😋 Promiseオブジェクトの使い方についてご紹介します♪

Promiseとは

まずポイントをチェック

  • 非同期処理の途中で利用されるオブジェクト
  • 非同期処理の結果によって処理を呼び分ける機能を持つ
  • 待機・成功・失敗の3つの状態を持つ

Promiseオブジェクトとは非同期処理で利用されるオブジェクトです。非同期な関数の戻り値としてPromiseオブジェクトが返却されます。

非同期処理はいつ結果が返ってくるか分かりません。Promiseは返ってきた結果に応じて処理を呼び分けます。

Promiseは内部に状態を持ちます。非同期処理の結果が返ってくるまでは待機状態です。結果が返ってくると成功状態になります。結果が不正な場合は失敗状態になります。

Promiseが成功状態になり、非同期処理の結果をプログラム上で受け取ることを「Promiseが解決された」と表現することもあります。

例えば、fetch関数での通信の場合、通信結果が返ってくるまでPromiseは待機状態です。通信結果が返ってくると成功状態になり、responseオブジェクトが取得できます。

😋 非同期処理の状態を管理するオブジェクトです♪

Promiseの状態遷移とコード

まずポイントをチェック

  • Promiseチェーン
    • 成功状態:thenの処理を実行
    • 失敗状態:catchの処理を実行
  • async/await
    • 成功状態:tryブロックの後続の処理を続行
    • 失敗状態:catchブロックの処理を実行

Promiseオブジェクトの状態の変化に対応した処理の書き方についてご紹介します。オーソドックスなPromiseチェーンと簡潔な記述な可能なasync/awiatのそれぞれでの書き方をご紹介します。

Promiseチェーン

Promiseチェーンの書き方の場合は、thenメソッドとcatchメソッドを利用します。

Promiseが成功状態の場合、thenメソッドに渡した処理が動作します。

Promiseが失敗状態の場合、catchメソッドに渡した処理が動作します。

下記の例はfetch関数をPromiseチェーンで利用しています。

// Promiseチェーン
fetch('URL')
    .then((response) => {
        console.log(response);
    })
    .catch((error) => {
        console.log(error);
    });

async/await

async/awaitの書き方の場合は、try-catchを利用します。

Promiseが成功状態の場合、tryブロックの後続の処理が動作します。

Promiseが失敗状態の場合、catchブロックに遷移し処理が動作します。

下記の例はfetch関数をasync/awaitで利用しています。

// async/await
const fn = async () => {
    try {
        const response = await fetch('URL');
        console.log(response);
    } catch (error) {
        console.log(error);
    }
};

😋 非同期処理の結果に応じて処理を呼び分けます♪

Promise対応した関数の作成

まずポイントをチェック

  • 多くの非同期処理はPromise対応している
  • Promiseを返さない非同期処理も存在する
  • Promise対応していない場合、自分でPromise対応させることも可能

多くの非同期処理はPromise対応していますが、ものによってはPromise対応していない非同期処理もあります。このような場合、自分でPromise対応させることができます。

Promise対応していない非同期処理はコールバック関数を活用した記述方式をとっています。この方法は非同期処理が連鎖した際に、コールバック関数のネストが深くなってしまうという問題があります。

また、Promise対応している他の処理と記述の統一性が損なわれてしまいます。

そこで、そういった非同期処理をPromise対応させます。

新しく関数を作成し、戻り値にPromiseオブジェクトを指定します。PromiseオブジェクトはPromiseコンストラクタで生成します。

Promiseコンストラクタの引数には関数を渡します。この関数は引数にresoleveとrejectという関数を受け取ります。resolveは元の非同期処理が成功した際に実行します。rejectは元の非同期処理が失敗した際に実行します。

Promiseを返す自作の関数例
// Promiseを返す関数を自作
const promiseFn = () => {
    return new Promise((resolve, reject) => {
        try {
            // throw new Error();
            resolve('成功');
        } catch {
            reject('失敗');
        }
    });
};

Promise化した関数を実行する際はasync/awaitやPromiseチェーンを利用することができます。

resolveの引数に渡した値は、Promise化した関数を実行しPromiseが成功状態になった際に取得できます。rejectの引数に渡した値は、Promise化した関数を実行しPromiseが失敗状態になった際に取得できます。

Promiseを返す関数を呼び出している例
const fn = async () => {
    try {
        const message = await promiseFn();
        console.log(message); // 成功
    } catch (error) {
        console.log(error); // 失敗
    }
};
fn();
fileReader.readAsDataURLメソッドをPromise化した例
// ファイル読み込み(非同期処理をPromise化)
const readFile = (file) => {
    return new Promise((resolve, reject) => {
        const fileReader = new FileReader();
        fileReader.addEventListener('load', (event) => { resolve(event.target.result) });
        fileReader.addEventListener('error', (event) => { reject('failed to read file') });
        fileReader.readAsDataURL(file);
    });
};

😋 Promise対応してない処理をPromise対応させることができます♪

おわりに

皆さん、お疲れ様でした。
ここまでご覧いただき、ありがとうございました。

Promiseオブジェクトについて確認をしていただきました。
多くの非同期処理はPromiseオブジェクトを返すようにできています。
また、Promiseに対応していない処理はPromise化させることもできますので、Promiseについて理解を深めていきましょう。

😋 これからもプログラミング学習頑張りましょう♪

参考リンク集
サンプルコード

Discussion