Mam aplikację, która wymaga załadowania danych w określonej kolejności: główny adres URL, następnie schematy, a na końcu zainicjuj aplikację ze schematami i adresami URL dla różnych obiektów danych. Gdy użytkownik nawiguje po aplikacji, obiekty danych są ładowane, sprawdzane względem schematu i wyświetlane. Gdy użytkownik CRUD dane, schematy zapewniają walidację pierwszego przejścia.
Mam problem z inicjalizacją. Używam wywołania Ajax, aby pobrać obiekt główny, $ .when (), a następnie tworzę tablicę obietnic, po jednej dla każdego obiektu schematu. To działa. Widzę pobieranie w konsoli.
Następnie widzę pobieranie dla wszystkich schematów, więc każde wywołanie $ .ajax () działa. fetchschemas () rzeczywiście zwraca tablicę obietnic.
Jednak ta ostatnia klauzula when () nigdy nie jest uruchamiana, a słowo „DONE” nigdy nie pojawia się na konsoli. Kod źródłowy jquery-1.5 wydaje się sugerować, że "null" jest akceptowalne jako obiekt do przekazania do $ .when.apply (), ponieważ when () zbuduje wewnętrzny obiekt Deferred () do zarządzania listą, jeśli żaden obiekt nie jest przeszedł.
To działało przy użyciu Futures.js. Jak należy zarządzać tablicą jQuery Deferreds, jeśli nie w ten sposób?
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);
});
});
źródło
Odpowiedzi:
Szukasz
$.when.apply($, promises).then(function(schemas) { console.log("DONE", this, schemas); }, function(e) { console.log("My ajax failed"); });
To również zadziała (dla pewnej wartości pracy nie naprawi zepsutego ajax):
$.when.apply($, promises).done(function() { ... }).fail(function() { ... });`
Będziesz chciał przejść
$
zamiast tegonull
, aby odnosiło się dothis
wnętrza . To nie powinno mieć znaczenia dla źródła, ale lepiej niż przejście .$.when
jQuery
null
Wyśmiewano wszystkie twoje $ .ajax, zastępując je
$.when
i próbka działaWięc jest to albo problem w twoim żądaniu Ajax, albo w tablicy, którą przekazujesz do fetch_schemas.
źródło
.then(a,b) === .done(a).fail(b)
to leniwy skrót. Możesz zadzwonić,.done(a).fail(b)
jeśli chcesz$.when.apply($, ...
. Tonull
sprawia, że mówię „czekaj, co?”. To kwestia stylu i praktyki kodowania. Musiałem przeczytać źródło, aby potwierdzić,this
że nie wrzucę zerowej referencji do jQuery.when!Powyższe obejście (dzięki!) Nie rozwiązuje poprawnie problemu odzyskiwania obiektów dostarczonych do metody deferred,
resolve()
ponieważ jQuery wywołuje wywołania zwrotnedone()
ifail()
z indywidualnymi parametrami, a nie tablicą. Oznacza to, że musimy użyćarguments
pseudo-tablicy, aby uzyskać wszystkie rozwiązane / odrzucone obiekty zwrócone przez tablicę deferreds, co jest brzydkie:$.when.apply($, promises).then(function() { var schemas=arguments; // The array of resolved objects as a pseudo-array ... };
Ponieważ przekazaliśmy tablicę odroczonych, dobrze byłoby otrzymać tablicę wyników. Byłoby również miło odzyskać rzeczywistą tablicę zamiast pseudo-tablicy, abyśmy mogli użyć takich metod, jak
Array.sort()
.Oto rozwiązanie zainspirowane metodą when.js ,
when.all()
które rozwiązuje te problemy:// 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; } }
Teraz możesz po prostu przekazać tablicę odroczonych / obietnic i odzyskać tablicę rozwiązanych / odrzuconych obiektów w swoim wywołaniu zwrotnym, na przykład:
$.when.all(promises).then(function(schemas) { console.log("DONE", this, schemas); // 'schemas' is now an array }, function(e) { console.log("My ajax failed"); });
źródło
apply()
...arguments
manipulacja we własnej metodzie. Świetne do ponownego wykorzystania, ale nie rozwiązuje problemu „brzydoty” konieczności radzenia sobiearguments
(możesz z łatwością po prostu:var schemas=Array.prototype.slice.call(arguments);)
deferred.fail(...)
czytaćdeferred.reject(...)
?Jeśli używasz javascript w wersji ES6 Istnieje operator spreadu (...), który konwertuje tablicę obiektów na argumenty oddzielone przecinkami.
$.when(...promises).then(function() { var schemas=arguments; };
Więcej o operatorze spreadu ES6 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator znajdziesz tutaj
źródło
rozszerza się, gdy z tym kodem:
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) } }
źródło