Promise〜例え話でわかるJSの概念〜 <- Node流並行処理 <- TetraCalibers
TetraCalibers :
    -   for : science student & programmer
Node流並行処理 - 2
Promise
例え話でわかるJSの概念

    Promise導入の動機

     

    もし、後続の処理を入れ子で書いていくのではなく、最初の処理.次の処理.その次の処理などと順番通りにつなげたチェーンのように書けたとしたら、とても読みやすいコードになる。

     

    これを実現するために、Promiseというオブジェクトが導入された。

     

    Promiseオブジェクトは、非同期処理の実行状況(実行中か、正常終了したか、エラーが出たか)を保持していて、それぞれの状態に応じた処理を記述するためのメソッドを提供する。

     

    非同期関数がその実行結果を保持しているPromiseオブジェクトを返すようにすると、JavaScriptのオブジェクト.メソッドという記法を使って、戻り値のPromiseオブジェクトがもつメソッドを続けて書くことができるようになる。

     

    このように、Promiseを導入することで、最初の処理.次の処理.その次の処理という時系列チェーンメソッド記法が実現される。

     

    アナロジー

     

    メリットはわかったが、結局Promiseという概念は何を表現・抽象化したものなのか。イメージを掴むために、例え話を作ってみる。

     

    素顔を隠して活動している大人気シンガー(あだ名:☆氏)は、事務所に押し寄せてくるパパラッチ集団に頭を悩ませていた。
    みんな彼の素顔を見たくて仕方がないのだ。

     

    ☆氏はこのパパラッチ問題を解決するため、思い切った決断をした。
    「次のライブで素顔を初公開する。だからそれまで待っていて欲しい」とファンに表明(約束)したのだ。
    また、「今後はパパラッチ行為に対して法的措置をとる」という警告も合わせて発表した。

     

    問題なくライブが開催できれば、素顔目当てで押し寄せてくるファンを満足させることができ、パパラッチ問題は円満に解決するだろう。

     

    しかし、コロナウイルスが蔓延するこのご時世、ライブが開催できるかはその時次第である。
    ライブが中止になった場合は、素顔を見たいファンの欲求を叶えることなく、ただ警告の通りにパパラッチ行為を拒否するだけとなる。

     

    …さて、ここでのキーワードは次の3つである。
    • 約束(Promise)
    • 解決(resolve)
    • 拒否(reject)

     

    『約束』という単語は時間差を孕んでいる。
    何らかの要求に対して、「今すぐやります!」と宣言するのではなく、「そうですね、タイミングが来たらやっておきましょう」と事前に約束するのだ。

     

    約束通りに処理が完了したら、要求された問題は解決する。
    処理の途中で不具合が起こった場合は、その要求を「今の私にはできません」と拒否することになる。

     

    状態とその遷移

     

    • pending$\cdots$結果が未確定な状態
    • settled$\cdots$結果が確定し、これ以上遷移しない状態
    settledは、次の2種類に分けられる。
    • fulfilled$\cdots$非同期処理に成功した状態
    • rejected$\cdots$非同期処理に失敗した状態

     

    前章で述べたように、非同期関数はPromiseオブジェクトを返すように実装する。
    function asyncProcessing() {
        return Promise((resolve, reject) =>
            setTimeout(() => {
                try {
                    resolve(処理結果)
                } catch (err) {
                    reject(err)
                }
            }, 1000)
        )
    }
    

     

    resolve(処理結果)
    pendingからfulfilledへと遷移させる(解決する)
    reject(エラー)
    pendingからrejectedへと遷移させる(拒否する)

     

    状態に応じた処理の登録

     

    then()
    Promiseオブジェクトの状態が確定したときに実行する処理を登録するメソッド

     

    promise.then(
        value => {
            成功時の処理
        }, 
        err => {
            失敗時の処理
        }
    )