web-dev-qa-db-ja.com

非同期JavaScript-コールバックと遅延/約束

可能性のある複製:
JavascriptのDeferred、Promise、Futureの違いは何ですか?

最近、JavaScriptアプリケーションの品質を改善するための努力をしています。

私が採用したパターンの1つは、別個の「データコンテキスト」オブジェクトを使用して、アプリケーションのデータをロードすることです(以前は、ビューモデルで直接これを行っていました)。

次の例は、クライアントで初期化されたデータを返します。

var mockData = (function($, undefined) {

    var fruit = [
        "Apple",
        "orange",
        "banana",
        "pear"
        ];

    var getFruit = function() {
        return fruit;
    };

    return {
        getFruit: getFruit
    }
})(jQuery);

ほとんどの場合、サーバーからデータをロードするため、すぐに応答を返すことはできません。 APIでこれを処理する方法には2つのオプションがあるようです。

  1. コールバックを使用する
  2. promise を返します。

以前は、常にコールバックアプローチを使用していました。

var getFruit = function(onFruitReady) {
    onFruitReady(fruit);
};

// ...

var FruitModel = function(dataContext, $) {
    return {
        render: function() {
            dataContext.getFruit(function(fruit) {
                // do something with fruit
            });
        }
    };
};

ただし、特に複雑なJavaScriptアプリケーションを構築する場合に、コールバック地獄に陥る可能性があることがわかります。

その後、Promisesのデザインパターンに出会いました。呼び出し元にコールバックを提供するよう要求する代わりに、私は代わりに観察できる「約束」を返します。

var getFruit = function() {
    return $.Deferred().resolve(fruit).promise();
};

// ...
dataContext.getFruit().then(function(fruit) {
    // do something with fruit
});

特に、単一のページアプリケーションの初期化データをロードする際に非常に役立つ複数の遅延オブジェクトに対してwaitできるため、このパターンを使用することの明らかな利点がわかります。

ただし、怒りのどちらかを使い始める前に、各パターンの長所と短所を理解したいと思っています。また、これが他のライブラリーが進む方向であるかどうかにも興味があります。jQueryの場合もそうです。

これは、テストに使用しているフィドルへの link です。

51
Ben Foster

また、約束は舞台裏のコールバックにも依存しているため、実際には一方と他方ではありません。

コールバックの利点は、単純なJavaScript(たとえば、ajax呼び出し)を使用して簡単に実装できることです。

Promiseには追加の抽象化レイヤーが必要です。これは通常、ライブラリに依存することを意味します(既にjQueryを使用しているため、問題ではありません)。複数の非同期呼び出しを並行して処理する場合に最適です。

18
Christophe

@Pointyがリンクしている jQuery docs を読むと、違いは、Deferred APIを使用すると、リクエストの完了時に呼び出される複数の関数を指定できるということのようです。

JQuery 1.5の時点で、エラー(失敗)、成功(完了)、および完了(常にjQuery 1.6の時点)コールバックフックは、先入れ先出しの管理キューです。つまり、各フックに複数のコールバックを割り当てることができます。これらの$ .ajax()コールバックフック用に内部的に実装される遅延オブジェクトメソッドを参照してください。

参照: deferred.then()

3
Max Fellows