jQuery Deferredの配列をどのように操作しますか?


132

データを特定の順序でロードする必要があるアプリケーションがあります。ルートURL、次にスキーマ、最後にさまざまなデータオブジェクトのスキーマとURLを使用してアプリケーションを初期化します。ユーザーがアプリケーションをナビゲートすると、データオブジェクトがロードされ、スキーマに対して検証され、表示されます。ユーザーがデータをCRUDすると、スキーマは初回パスの検証を提供します。

初期化に問題があります。Ajax呼び出しを使用してルートオブジェクト$ .when()をフェッチし、スキーマオブジェクトごとに1つずつ、promiseの配列を作成します。うまくいきます。コンソールにフェッチが表示されます。

次に、すべてのスキーマのフェッチが表示されるので、各$ .ajax()呼び出しが機能します。fetchschemas()は確かにpromiseの配列を返します。

ただし、その最後のwhen()句は起動せず、「DONE」という単語はコンソールに表示されません。jquery-1.5のソースコードは、$。when.apply()に渡すオブジェクトとして「null」が受け入れられることを示唆しているようです。渡された。

これはFutures.jsを使用して機能しました。このようにならない場合、jQuery Deferredの配列はどのように管理する必要がありますか?

    var fetch_schemas, fetch_root;

    fetch_schemas = function(schema_urls) {
        var fetch_one = function(url) {
            return $.ajax({
                url: url,
                data: {},
                contentType: "application/json; charset=utf-8",
                dataType: "json"
            });
        };

        return $.map(schema_urls, fetch_one);
    };

    fetch_root = function() {
        return $.ajax({
            url: BASE_URL,
            data: {},
            contentType: "application/json; charset=utf-8",
            dataType: "json"
        });
    };

    $.when(fetch_root()).then(function(data) {
        var promises = fetch_schemas(data.schema_urls);
        $.when.apply(null, promises).then(function(schemas) {
            console.log("DONE", this, schemas);
        });
    });

「DONE」が出力される前に、fetch_oneの各ajaxクエリに対して「成功」メソッドを起動する必要があることを除いて、ほぼ同じ問題があります。これをどうやってやりますか?「fetch_one」の後に.pipeを使用してみましたが、うまくいきませんでした。
CambridgeMike

回答:


198

あなたが探しています

$.when.apply($, promises).then(function(schemas) {
     console.log("DONE", this, schemas);
}, function(e) {
     console.log("My ajax failed");
});

これも機能します(一部の機能については、壊れたajaxは修正されません)。

$.when.apply($, promises).done(function() { ... }).fail(function() { ... });` 

内部がを参照するように、$代わりに渡す必要があります。ソースには関係ありませんが、を渡すよりも優れています。nullthis$.whenjQuerynull

$ .ajaxをすべて置き換えることでモックアウトし$.when、サンプルが機能するようにしました

したがって、それはあなたのajaxリクエストの問題か、fetch_schemasに渡す配列のどちらかです。


ありがとうございました。この構文は、done()。fail()とどのように異なりますか?
Elf Sternberg

2
@elf Sternberg、.then(a,b) === .done(a).fail(b)それは怠惰な省略表現です。.done(a).fail(b)必要に応じて電話をかけることができます
レイノス

1
ああ、そして$ .when.apply($、...)と$ .when.apply(null、...)の使用は無関係のようです。jQuery自体にはpromise()メソッドがないため、内部で生成されたDeferredオブジェクト(jQuery 1.5、行943)のために無視されます。
Elf Sternberg

1
@ElfSternbergは実際には無関係ですが、読みやすくするためにをもう一度見直す必要はありません$.when.apply($, ...null私が行かせる「何を待つのか?」。それはスタイルとコーディング慣行の問題です。ソースを読み取ってthisjQuery.when内でnull参照がスローされないことを確認する必要がありました。
レイノス

7
nullを使用すると、「大丈夫、これは一種の回避策です」(そうです)と思いますが、$が使用された場合、注意は$ fのwtfについて考えることに回されます。
Danyal Aytekin

53

上記の回避策(ありがとう!)ではresolve()、jQueryがdone()fail()コールバックを配列ではなく個々のパラメーターで呼び出すため、遅延オブジェクトのメソッドに提供されたオブジェクトを取得する問題に適切に対処できません。これは、arguments疑似配列を使用して、遅延オブジェクトの配列によって返されたすべての解決済み/拒否されたオブジェクトを取得する必要があることを意味します。

$.when.apply($, promises).then(function() {
     var schemas=arguments; // The array of resolved objects as a pseudo-array
     ...
};

遅延オブジェクトの配列を渡したので、結果の配列を取得すると便利です。また、擬似配列の代わりに実際の配列を取得して、次のようなメソッドを使用できるようにするとよいでしょう。Array.sort()

これらの問題に対処するwhen.jswhen.all()メソッドから着想を得た解決策を次に示します。

// Put somewhere in your scripting environment
if (jQuery.when.all===undefined) {
    jQuery.when.all = function(deferreds) {
        var deferred = new jQuery.Deferred();
        $.when.apply(jQuery, deferreds).then(
            function() {
                deferred.resolve(Array.prototype.slice.call(arguments));
            },
            function() {
                deferred.fail(Array.prototype.slice.call(arguments));
            });

        return deferred;
    }
}

次のように、単にdeferreds / promisesの配列を渡し、解決済み/拒否されたオブジェクトの配列をコールバックで返すことができます。

$.when.all(promises).then(function(schemas) {
     console.log("DONE", this, schemas); // 'schemas' is now an array
}, function(e) {
     console.log("My ajax failed");
});

@crispyduck-then()の "schemas"変数の配列要素の順序がwhenの "promises"変数のajax呼び出しと常に同じ順序になることを100%確信できるかどうか知っていますか()?
netpoetica 2014年

6
これは単にjQueryに組み込まれるべきですが、jQueryチームは何度もリクエストを拒否しました。その間、人々はここで質問を続け、jQueryに対して同様のチケットをオープンし、私たちはどこにでもユーザーランドの実装を作成したり、厄介な呼び出しをapply()行ったりして... わかりました。
mindplay.dk 14

この解決策をありがとう!1つ(または複数)が失敗した場合にも成功したアイテムを取得する方法はありますか?
ドクトリアス2015

ここで行ったことはarguments、独自のメソッドへの隠された操作だけです。再使用のために大きいが、に対処することの「醜さ」を扱っていないarguments(あなたが簡単だけかもしれない:var schemas=Array.prototype.slice.call(arguments);)
cowbert

2
@crispyduck、deferred.fail(...)読んではいけdeferred.reject(...)ませんか?
Bob S

19

JavaScriptのES6バージョンを使用している場合オブジェクトの配列をコンマ区切りの引数に変換するスプレッド演算子(...)があります。

$.when(...promises).then(function() {
 var schemas=arguments; 
};

ES6スプレッドオペレーターの詳細https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operatorこちらをご覧ください


1
うん。Coffeescriptまたはその子孫/模倣者の1人を使用している私たちの人々は、しばらくの間そのオペレーターにアクセスできましたが。
Elf Sternberg

0

このコードで拡張します:

var rawWhen = $.when
$.when = function(promise) {
    if ($.isArray(promise)) {
        var dfd = new jQuery.Deferred()
        rawWhen.apply($, promise).done(function() {
            dfd.resolve(Array.prototype.slice.call(arguments))
        }).fail(function() {
            dfd.reject(Array.prototype.slice.call(arguments))
        })
        return dfd.promise()
    } else {
        return rawWhen.apply($, arguments)
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.