5

jQueryライブラリの「約束」の回避を主張する新しいEMCAの約束に関する多くのチュートリアルを見てきました。彼らは通常、次のようなことを行うことでそれらをかわすことができると言います:

Promise.resolve($.getJSON(url, params)); // voila!  the jQuery promise is "gone"!

ただし、2 つの非同期 jQuery 関数を一緒にチェーンする必要がある場合、これは実際には機能しません。jQuery の then() または .when() を使用せずに、2 つの getJSON 呼び出し (2 番目の呼び出しが最初の呼び出しに依存する) をチェーンするにはどうすればよいですか?

代わりに、Promise.all などを使用したいだけです。

同様の質問の問題は、jquery と EMCA の約束をインターリーブすることだと思いますか?

4

2 に答える 2

7

JavaScript の promise は相互運用可能です。必要に応じてそれらを混在させることができます。すべての適切なライブラリ1とネイティブの promiseは、任意の実装からのthenable 2を受け入れます3。何か異質なものが現れた場合、彼らはただそれに対処Promise.resolveします。

したがって、通常は、すべてが同じ promise 実装を使用しているかのようにコードを記述し、それが機能します。
ただし、ここでは、すべての.thenメソッド呼び出しがお気に入りの実装を使用していることを確認する必要があります。または、非標準の方法や機能を使用したいですか? そのためには、メソッドを直接呼び出すすべての promise を明示的にキャストする必要があります。

いくつかの例:

Promise.all([$.ajax(…), $.ajax(…)]).then(…); // just works!
$.ajax(…) // a jQuery promise
.then(…)  // so this would be jQuery `then`, which we don't want.
Promise.resolve($.ajax(…)) // explicit cast
.then(function(data) {     // native `then`
    return $.ajax(…);      //   just works!
})                         // returns a native promise still
.catch(…)                  // so we can use its features

1: ええ、jQuery はバージョン 3.0 までそれらの 1 つではありませんでした
2: すべての jQuery の deferred と promise はそのようなthenablesですが、
3: 実際には、promise を期待するすべての場所でPromise.resolveコールバックのthen戻り値、Promise.all引数、…</sub>

于 2015-07-09T20:36:43.293 に答える
7

2つのアプローチのいずれかを採用できます...

変換してから結合:

var p1 = Promise.resolve($.getJSON(url_1, params_1)); // voila 1!
var p2 = Promise.resolve($.getJSON(url_2, params_2)); // voila 2!
var p3 = Promise.all([p1, p2]).then(...);

結合してから変換:

var p1 = $.getJSON(url_1, params_1);
var p2 = $.getJSON(url_2, params_2);
var p3 = Promise.resolve($.when(p1, p2)).then(...); // voila 1 and 2!

簡単に言えば、どちらのアプローチでもネイティブ ES6 promise が得られます。p3これは、両方の jQuery promise が解決されたときに解決されるか、いずれかの promise が失敗したときに拒否されます。

ただし、おそらく 2 つの呼び出しの結果に関心があるでしょうがgetJSON()、jQuery はこの点で厄介です。jQuery の jqXHR promise は、成功およびエラー コールバックに複数のパラメータを渡しますが、ES6 promise は 1 つだけを受け入れます。残りは無視されます。幸いなことに、複数のパラメーターをまとめて 1 つのオブジェクトを作成するのは非常に簡単です。これは、ES6 に変換する前に jQuery で行う必要があります。

「変換してから結合」コードは次のように展開されます。

var p1 = Promise.resolve($.getJSON(url_1, params_1).then(
    function(data, textStatus, jqXHR) {
        return { data:data, textStatus:textStatus, jqXHR:jqXHR };
    },
    function(jqXHR, textStatus, errorThrown) {
        return { jqXHR:jqXHR, textStatus:textStatus, errorThrown:errorThrown };
    }
));
var p2 = Promise.resolve($.getJSON(url_2, params_2).then(
    function(data, textStatus, jqXHR) {
        return { data:data, textStatus:textStatus, jqXHR:jqXHR };
    },
    function(jqXHR, textStatus, errorThrown) {
        return { errorThrown:errorThrown, textStatus:textStatus, jqXHR:jqXHR };
    }
));
var p3 = Promise.all([p1, p2]).then(
    function(results) {
        // results[0] will be an object with properties .data, .textStatus, .jqXHR 
        // results[1] will be an object with properties .data, .textStatus, .jqXHR 
    },
    function(rejectVal) {
        // rejectVal will be an object with properties .errorThrown, .textStatus, .jqXHR
    }
);

"結合してから変換する" アプローチは、結合された結果が (jQuery で)argumentsリストとして表示され、それ自体を (まだ jQuery で) 配列に変換する必要があるため、少しトリッキーです。

var p1 = $.getJSON(url_1, params_1).then(
    function(data, textStatus, jqXHR) { 
        return { data:data, textStatus:textStatus, jqXHR:jqXHR }; 
    },
    function(jqXHR, textStatus, errorThrown) { 
        return { errorThrown:errorThrown, textStatus:textStatus, jqXHR:jqXHR }; 
    }
);
var p2 = $.getJSON(url_2, params_2).then(
    function(data, textStatus, jqXHR) { 
        return { data:data, textStatus:textStatus, jqXHR:jqXHR };
    },
    function(jqXHR, textStatus, errorThrown) { 
        return { errorThrown:errorThrown, textStatus:textStatus, jqXHR:jqXHR }; 
    }
);
var p3 = Promise.resolve($.when(p1, p2).then(function() {
    return [].slice.call(arguments);// <<< convert arguments list to Array
})).then(
    function(results) { 
        // results[0] will be an object with properties .data, .textStatus, .jqXHR
        // results[1] will be an object with properties .data, .textStatus, .jqXHR
    },
    function(rejectVal) { 
        // rejectVal will be an object with properties .errorThrown, .textStatus, .jqXHR
    }
);

デモ: 解決済み

デモ: 却下

于 2015-07-10T09:09:02.340 に答える