2016-02-13 7 views
5

私は最終的にjavascript/ES6 Promisesの周りで私の心を曲げることができたと思います。それは簡単ではなかった!しかし、デザインについて私を困惑させる何かがあります。javascript Promise APIは、必要以上に畳み込まれていますか?

なぜPromiseコンストラクタがコールバックを取るのですか?コールバックがすぐに呼び出されると、呼び出し元はそのコードを実行するだけで、「私に電話しないで、私はあなたに電話します」という心配の1つの不必要なレベルを回避できますか?

ここでは、Jake ArchibaldのJavascript Promisesチュートリアルhttp://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequestからコピーされたPromiseの使用例のプロトタイプの例を、コメントを削除して考えています。

それはXMLHttpRequestをGETリクエストのための約束ベースのラッパーです:私にとって

function get(url) { 
    return new Promise(function(resolve, reject) { 
    var req = new XMLHttpRequest(); 
    req.open('GET', url); 
    req.onload = function() { 
     if (req.status == 200) { 
     resolve(req.response); 
     } 
     else { 
     reject(Error(req.statusText)); 
     } 
    }; 
    req.onerror = function() { 
     reject(Error("Network Error")); 
    }; 
    req.send(); 
    }); 
} 

、上記のコードは、約束の非常にわずかに異なる種類を使用して、次のようにそれが書き直された場合に理解することが非常に容易になるだろう私は、想像引数なしのコンストラクタを持つと解決/メソッドを拒否してること:

function get(url) { 
    var promise = new MyEasierToUnderstandPromise(); 
    var req = new XMLHttpRequest(); 
    req.open('GET', url); 
    req.onload = function() { 
    if (req.status == 200) { 
     promise.resolve(req.response); 
    } 
    else { 
     promise.reject(Error(req.statusText)); 
    } 
    }; 
    req.onerror = function() { 
    promise.reject(Error("Network Error")); 
    }; 
    req.send(); 
    return promise; 
} 

MyEasierToUnderstandPromiseプロミスの面で実装するにはあまりにも難しいことではありません。最初はプロミスの実際のサブクラスにしようとしましたが、何らかの理由でそれを動作させることができませんでした。その代わりに、私はメンバ関数のように振る舞う添付余分な機能 のカップルと、昔ながらのPromiseオブジェクトを返す単純なファクトリ関数、としてそれを実装:

だから、
function NewMyEasierToUnderstandPromise() { 
    var resolveVar; 
    var rejectVar; 
    var promise = new Promise(function(resolveParam, rejectParam) { 
    resolveVar = resolveParam; 
    rejectVar = rejectParam; 
    }); 
    promise.resolve = resolveVar; 
    promise.reject = rejectVar; 
    return promise; 
}; 

、なぜこのように設計された約束されていませんか?それがあれば、約束をもっと早く理解できるようになりました。私の学習時間を半減させたと思います。

私は多くのスマートな人がプロミスAPIの作成に手を携えていたことを知っています。誰もが一般的に幸せで誇りに思えるので、彼らは何を考えているのだろうかと思います。

+1

あなたの「easierToUnderstandPromiseは」の方法でjQuery.Deferredのようなものです。あなたの設計では、返された約束は必ず解決/拒否の方法を公開します。私はなぜこれが「悪い」ものなのか読んだことがありますが、そのリソースを見つけることができませんでした。(それを読んでから何年も経ちました) –

+0

[ES7 async/await](https://jakearchibald.com/2014)/es7-async-functions /)を実行します。 –

+0

遅延パターンもありますが、正当な理由で廃止されました。(http://stackoverflow.com/q/28687566/1048572) – Bergi

答えて

6

あなたのバージョンは例外セーフではありませんが、プロンプト/ A +はPromiseコンストラクタによって捕捉されているので安全です。スクリプトが約束変数が.catchメソッドの呼び出しによって返された約束に設定を残している

var promise = new Promise(executor).then(something).catch(handleError); 

等ES6約束チェーンを定義ancilliary情報として

+0

偉大な答え、ありがとうございます。私はすべての入門書やチュートリアルは、これを言及することで大幅に改善されると思う - 私の脳は、理由を見ることができないものを吸収したくない! –

1

、。チェーン全体またはPromiseオブジェクトは、実際にはexecutor関数によって保持されている解決/拒否関数参照によってガベージコレクションされることはありません。 resolveが呼び出された場合(通常はエグゼキュータが復帰した後、解決/拒否機能を有効範囲外にする前に)、thenリスナー「something」が呼び出され、Promiseプラットフォームの内部実行プログラムが返された約束の解決/ then呼び出しを防止し、その後の連鎖したすべての約束事が早すぎてガベージコレクションされるようにします。

遅延モデルでは、この問題を解決または拒否するには、の最初のプロミスへの参​​照が必要なため、このような方法でプロミスチェーンを設定することはできません。コードは、操作レスポンスコード

promise.resolve(value); // if no error occurred 
promise = null;   // explicit discard of first promise reference to allow GC? 

で非同期的に、より多くの

var promise = new Promise(); // no executor 
promise.then(something).catch(handleError); 
initiateOperation(promise); 

ようになり、ES6の一般的なアプローチはminimilistic(痛い)を有望に見えるし始め、今お約束します。私は約束の仕方を学ぶ上でのあなたの困難を共感します。興味深い旅です!!!

+1

いいえ、executorスコープ内の 'resolve' /' reject'への参照を明示的に破棄する必要がないように、非同期コールバックで 'promise'への参照を明示的に破棄する必要はありません。 – Bergi

5

約束は値として使用することを意図しています。 ESコンストラクタのアプローチは、プロミスの作成をカプセル化し、それを値のように渡すことができます。その値が渡されるとき、その値の消費者はresolverejectの必要がないので、それらの関数はパブリックAPIの一部であってはいけません。

(例外処理やチェーンに関するすべてのもの)

関連する問題