【JavaScript】Promiseオブジェクト

Promiseとは

JavaScriptの非同期処理のネストを深くせずに実装することができる仕組み。

背景

  • コールバック地獄
    JavaScriptの非同期処理はコールバック関数を利用して実装するが、処理が連続するとネストが深くなり、コードが肥大化してしまう問題があった。
// 引数を倍にする関数
function async(data, callback) {
    setTimeout(function() {
        callback(data * 2);
    }, 1000);
}

function callback_hell() {
    async(100, function(data) {
        console.log(data);// => 200
        async(data, function(data) {
            console.log(data);// => 400
            async(data, function(data) {
                console.log(data);// => 800
            });
        });
    });
}

そのため、連続する非同期処理をネストを深くせず同期処理のように記載するためにPromiseが利用される。

実装例

//Promiseオブジェクト
const async = value => {
    return new Promise((resolve,reject) => {
        setTimeout(()=>{
            if(value) {
                console.log(value)
                resolve('success')
            }else{
                console.log('値なし')
                reject('failure')
            }
        },1000)
    })
}
//thenメソッド
async('test1').then(
    response => {
        // => test1
        return async('test2')
        // => test2
    }
  ).then(
    response => { 
    },
    error => {
      console.log('エラー')
    }
)
  • Promiseオブジェクト
    非同期処理の最終的な完了もしくは失敗を表すオブジェクト
    Promiseオブジェクトのコンストラクターには3つの引数が必要。

    function(resolutionFunc, rejectionFunc){
    // typically, some asynchronous operation.
    }

    • resolutionFunc
      処理の成功を通知するための関数
    • rejectionFunc
      処理の失敗を通知するための関数
    • asynchronous operation
      処理本体

      上記コードでは処理としてseTimeOutを実行し、引数があればresolve,なければrejectを呼び出している。

  • thenメソッド
    Promiseが成功した場合と失敗した場合のコールバック関数を受け取るメソッド。

    p.then(onFulfilled[, onRejected]);
    p.then(value => {
    // fulfillment
    }, reason => {
    // rejection
    });

    • onFulfilled
      Promiseが成功した時に呼び出される関数(resolveによって呼び出し)
    • onRejected
      Promiseが失敗した時に呼び出される関数(rejectによって呼び出し)

メリット

  • 連続する非同期処理をネストせずに書ける
    Promiseを利用することで連続する非同期処理をthenメソッドでつなぐことができるため、コールバック地獄を回避でき、メソッドが肥大化することを防止できる。

  • エラー処理を必要な箇所にまとめることができる
    Promiseを利用することで、どの処理でエラーになってもthenメソッドで用意した失敗コールバック関数(reject)が呼び出されるため、メソッドごとにエラー処理を記載する必要がない。

参考