JavaScript Promiseオブジェクト

7275 ワード

Promiseオブジェクトには以下の2つの特徴があります.
1、対象の状態は外部の影響を受けない.Promiseオブジェクトは、非同期動作を表し、3つの状態がある:−pending:初期状態は、成功または失敗状態ではない.
  • fulfilled:動作が成功したことを意味する.rejected:動作失敗を意味する.非同期操作の結果のみ、現在の状態はどの状態かを決定できます.他の操作はこの状態を変えることができません.これもPromiseという名前の由来で、英語の意味は「承諾」で、他の手段が変えられないという意味です.
  • 2、一旦状態が変わったら、二度と変わらない.いつでもこの結果を得ることができる.Promiseオブジェクトの状態変化は、PendingからResolvedに変化し、PendingからRejectedに変化することができる2つだけである.この二つの状況が発生すれば、状態が固まり、これ以上変わることなく、ずっとこの結果を維持します.変更が発生したとしても、Promiseオブジェクトに対してコールバック関数を追加すると、すぐにこの結果が得られます.イベントとは全く違って、イベントの特徴は、それを見逃してしまったら、また傍聴しても結果が得られないということです.
    Promiseの長所と短所
    Promiseオブジェクトがあると、非同期動作の流れを同期させて表現でき、入れ子の回転関数が回避されます.また、Promiseオブジェクトは、非同期動作を制御することが容易になるように、統一されたインターフェースを提供する.
    Promiseにもいくつかの欠点があります.まず、Promiseをキャンセルすることができません.新築したらすぐ実行します.途中でキャンセルできません.次に、コールバック関数を設定しないと、Promise内部で投げられたエラーは外部に反応しません.第三に、Pendingの状態では、どの段階に進行しているかが分かりません.
    Promiseの作成
    プロミセオブジェクトを作成するには、newを使ってPromiseのコンストラクタを呼び出して実装することができます.
    以下はプロモーションを作成するステップです.
    var promise = new Promise(function(resolve, reject) {
        //     
        //      、  resolve   reject
    });
    
    Promiseコンストラクタは、一つのパラメータと一つのresolve( )reject( )と二つのパラメータを有するリピートを含む.コールバックでいくつかの動作(例えば、非同期)が実行され、すべてが正常であればresolveを呼び出し、そうでなければrejectを呼び出す.
    var myFirstPromise = new Promise(function(resolve, reject){
        //          ,      resolve(...),             reject(...)
        //    ,    setTimeout(...)       ,        XHR    HTML5   API  .
        setTimeout(function(){
            resolve("  !"); //      !
        }, 250);
    });
     
    myFirstPromise.then(function(successMessage){
        //successMessage       resolve(...)      .
        //successMessage             ,        
        document.write("Yay! " + successMessage);
    });
    
    すでに実装されているpromiseオブジェクトについては、promise.then()方法を呼び出すことができ、フィードバックとしてresolve reject方法を伝えることができる.
    promise.thenはpromiseで一番よく使われる方法です.
    promise.then(onFulfilled, onRejected)
    
    promiseはerrorに対する処理を簡略化しました.上のコードは私達もこのように書くことができます.
    promise.then(onFulfilled).catch(onRejected)
    
    Promise Ajax
    以下はPromiseオブジェクトで実現されるAjax操作の例です.
    function ajax(URL) {
        return new Promise(function (resolve, reject) {
            var req = new XMLHttpRequest(); 
            req.open('GET', URL, true);
            req.onload = function () {
            if (req.status === 200) { 
                    resolve(req.responseText);
                } else {
                    reject(new Error(req.statusText));
                } 
            };
            req.onerror = function () {
                reject(new Error(req.statusText));
            };
            req.send(); 
        });
    }
    var URL = "/try/ajax/testpromise.php"; 
    ajax(URL).then(function onFulfilled(value){
        document.write('   :' + value); 
    }).catch(function onRejected(error){
        document.write('  :' + error); 
    });
    
    上記のコードには、resolve方法とreject方法の呼び出し時にパラメータが付いています.それらのパラメータはコールバック関数に伝達されます.reject方法のパラメータは、典型的にはErrオブジェクトの例であり、resolve方法のパラメータは、通常の値に加えて、次のような他のPromise例でもある.
    var p1 = new Promise(function(resolve, reject){
      // ... some code
    });
     
    var p2 = new Promise(function(resolve, reject){
      // ... some code
      resolve(p1);
    })
    
    上記のコードでは、p1 p2Promiseの例であるが、p2resolveの方法はp1をパラメータとしている.このとき、p1の状態はp2に伝達される.呼び出し時にp1の状態がpendingであると、p2のコールバック関数はp1の状態変化を待つことになる.p1の状態がすでにfulfilledまたはrejectedである場合、p2のコールバック関数は直ちに実行される.
    Promise.prototype.then方法:チェーン操作Promise.prototype.then方法で戻ってきたのは新しいPromiseオブジェクトですので、チェーン式の書き方ができます.
    getJSON("/posts.json").then(function(json) {
      return json.post;
    }).then(function(post) {
      // proceed
    });
    
    上のコードはthenメソッドを使用して、二つのコールバック関数を順次指定しました.最初のコールバック関数が完了したら、戻り結果をパラメータとして、2番目のコールバック関数に伝えます.
    前のコールバック関数がPromiseオブジェクトに戻った場合、次のコールバック関数はこのPromiseオブジェクトの実行結果を待って、さらに呼び出します.
    getJSON("/post/1.json").then(function(post) {
      return getJSON(post.commentURL);
    }).then(function(comments) {
      //  comments    
    });
    
    この設計は入れ子の非同期動作を容易に書き換えられ,反転関数の「横方向発展」から「下方向発展」に変えた.
    Promise.prototype.catch方法:キャプチャエラーPromise.prototype.catch方法は、エラーが発生した場合のコールバック関数を指定するPromise.prototype.then(null, rejection)の別名である.
    getJSON("/posts.json").then(function(posts) {
      // some code
    }).catch(function(error) {
      //                  
      console.log('    !', error);
    });
    
    Promiseオブジェクトのエラーは「泡が出る」という性質を持ち、捕獲されるまで後進的に伝えられます.つまり、エラーはいつも次のcatch文に捕獲されます.
    getJSON("/post/1.json").then(function(post) {
      return getJSON(post.commentURL);
    }).then(function(comments) {
      // some code
    }).catch(function(error) {
      //             
    });
    
    Promise.allメソッド、Promise.raceメソッドPromise.all方法は、複数のPromiseの例を新たなPromiseの例に包装するために使用される.
    var p = Promise.all([p1,p2,p3]);
    
    上記のコードでは、Promise.all方法は、パラメータとして1つの配列を受け入れています.p 1、p 2、p 3は、Promiseオブジェクトの例です.(Promise.all方法のパラメータは必ずしも配列ではないが、iteratorインターフェースを持っていなければならず、戻ってくる各メンバはPromiseの例である.)
    pの状態はp 1、p 2、p 3で決まります.
  • (1)p 1、p 2、p 3だけの状態がフルフィルドになり、pの状態がフルフィルドになり、p 1、p 2、p 3の戻り値が1つの配列をなしてpに伝達されるコールバック関数となる.
  • (2)p 1、p 2、p 3の中にrejectdがある限り、pの状態はrejectとなり、このとき最初にrejectのインスタンスの戻り値がpのコールバック関数に伝達される.以下は具体的な例です.
  • //     Promise     
    var promises = [2, 3, 5, 7, 11, 13].map(function(id){
      return getJSON("/post/" + id + ".json");
    });
     
    Promise.all(promises).then(function(posts) {
      // ...  
    }).catch(function(reason){
      // ...
    });
    
    Promise.race方法は、複数のPromiseの例を、新たなPromiseの例として包装するものである.
    var p = Promise.race([p1,p2,p3]);
    
    上記のコードにおいて、p1、p2、p3のうちの1つのインスタンスが率先して状態を変更する限り、pの状態は変化する.その先に変わったPromiseの例の戻り値は、pの戻り値に伝えられる.
    もし`Promise.all方法とPromise.race方法のパラメータがPromiseの例ではないなら、先に以下に述べたPromise.resove方法を呼び出して、パラメータをPromiseの例に変えて、さらに処理します.
    Promise.reolve方法、Promise.reject方法
    既存のオブジェクトをPromiseオブジェクトに変換する必要があります.Promise.resove方法はこの役割を果たします.
    var jsPromise = Promise.resolve($.ajax('/whatever.json'));
    
    上のコードはjQueryをdeferredオブジェクトに生成し、新しいES 6のPromiseオブジェクトに変換します.Promise.resolve方法のパラメータが、then方法のオブジェクト(thenableオブジェクトとも呼ばれる)でない場合、新しいPromiseオブジェクトに戻り、fulfilledの状態になる.
    var p = Promise.resolve('Hello');
     
    p.then(function (s){
      console.log(s)
    });
    // Hello
    
    上のコードは新しいPromiseオブジェクトのインスタンスpを生成し、その状態はfulfilledであるため、コールバック関数は直ちに実行され、Promise.resolve方法のパラメータはコールバック関数のパラメータである.Promise.resolve方法のパラメータがPromiseオブジェクトの一例である場合、そのまま返されます.Promise.reject(reason)方法は、Promise方法のパラメータreasonであり、インスタンスのコールバック関数に伝達される新しいrejected。Promise.reject例を返します.
    var p = Promise.reject('   ');
     
    p.then(null, function (s){
      console.log(s)
    });
    //