Przekazać w tablicy Deferreds do $.kiedy()
Oto wymyślony przykład tego, co się dzieje: http://jsfiddle.net/adamjford/YNGcm/20/
HTML:
<a href="#">Click me!</a>
<div></div>
JavaScript:
function getSomeDeferredStuff() {
var deferreds = [];
var i = 1;
for (i = 1; i <= 10; i++) {
var count = i;
deferreds.push(
$.post('/echo/html/', {
html: "<p>Task #" + count + " complete.",
delay: count
}).success(function(data) {
$("div").append(data);
}));
}
return deferreds;
}
$(function() {
$("a").click(function() {
var deferreds = getSomeDeferredStuff();
$.when(deferreds).done(function() {
$("div").append("<p>All done!</p>");
});
});
});
Chcę " wszystko gotowe!"pojawia się po wykonaniu wszystkich zadań odroczonych, ale $.when()
nie zdaje się wiedzieć, jak obsługiwać tablicę obiektów odroczonych. "Gotowe!"dzieje się najpierw, ponieważ tablica nie jest obiektem odroczonym, więc jQuery idzie naprzód i zakłada, że jest po prostu zrobione.
Wiem, że można przejść przez obiekty do funkcji jak $.when(deferred1, deferred2, ..., deferredX)
, ale nie wiadomo, ile obiektów odroczonych będzie w trakcie wykonywania w rzeczywistym problemie, który próbuję rozwiązać.
9 answers
Aby przekazać tablicę wartości do dowolnej funkcji , która normalnie oczekuje, że będą oddzielnymi parametrami, użyj Function.prototype.apply
, więc w tym przypadku potrzebujesz:
$.when.apply($, my_array).then( ___ );
Zobacz http://jsfiddle.net/YNGcm/21/
W ES6 możesz użyć ...
operator spreadu zamiast:
$.when(...my_array).then( ___ );
W obu przypadkach, ponieważ jest mało prawdopodobne, abyś wiedział z góry, ile formalnych parametrów będzie wymagał .then
, ten handler musi przetworzyć tablicę arguments
, aby Odzyskaj wynik każdej obietnicy.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-06 16:50:23
Obejścia powyżej (dzięki!) nie rozwiązuje problemu odzyskania obiektów dostarczonych do metody resolve()
deferred, ponieważ jQuery wywołuje wywołania zwrotne done()
i fail()
z indywidualnymi parametrami, a nie tablicą. Oznacza to, że musimy użyć pseudo-tablicy arguments
, aby uzyskać wszystkie rozwiązane / odrzucone obiekty zwrócone przez tablicę deferredów, co jest brzydkie:
$.when.apply($,deferreds).then(function() {
var objects=arguments; // The array of resolved objects as a pseudo-array
...
};
Ponieważ przeszliśmy w tablicy odroczeń, byłoby miło odzyskać tablicę wyników. Byłoby byłoby też miło odzyskać rzeczywistą tablicę zamiast pseudo-tablicy, abyśmy mogli używać metod takich jak Array.sort()
.
Oto rozwiązanie inspirowane kiedy.metoda js'S when.all()
, która rozwiązuje te problemy:
// Put somewhere in your scripting environment
if (typeof jQuery.when.all === 'undefined') {
jQuery.when.all = function (deferreds) {
return $.Deferred(function (def) {
$.when.apply(jQuery, deferreds).then(
function () {
def.resolveWith(this, [Array.prototype.slice.call(arguments)]);
},
function () {
def.rejectWith(this, [Array.prototype.slice.call(arguments)]);
});
});
}
}
Teraz możesz po prostu przekazać tablicę deferreds / promises i odzyskać tablicę rozwiązanych / odrzuconych obiektów w Twoim wywołaniu zwrotnym, tak:
$.when.all(deferreds).then(function(objects) {
console.log("Resolved objects:", objects);
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-20 12:47:59
Możesz zastosować metodę when
do tablicy:
var arr = [ /* Deferred objects */ ];
$.when.apply($, arr);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:36
Podczas wywoływania wielu równoległych wywołań AJAX, masz dwie opcje obsługi odpowiednich odpowiedzi.
- Użyj synchronicznego wywołania AJAX / jedno po drugim/ nie zalecane
- Użyj
Promises'
tablicy i$.when
który akceptujepromise
s i jego wywołanie zwrotne.done
zostanie wywołane, gdy wszystkiepromise
s powrócą pomyślnie z odpowiednimi odpowiedziami.
Przykład
function ajaxRequest(capitalCity) {
return $.ajax({
url: 'https://restcountries.eu/rest/v1/capital/'+capitalCity,
success: function(response) {
},
error: function(response) {
console.log("Error")
}
});
}
$(function(){
var capitalCities = ['Delhi', 'Beijing', 'Washington', 'Tokyo', 'London'];
$('#capitals').text(capitalCities);
function getCountryCapitals(){ //do multiple parallel ajax requests
var promises = [];
for(var i=0,l=capitalCities.length; i<l; i++){
var promise = ajaxRequest(capitalCities[i]);
promises.push(promise);
}
$.when.apply($, promises)
.done(fillCountryCapitals);
}
function fillCountryCapitals(){
var countries = [];
var responses = arguments;
for(i in responses){
console.dir(responses[i]);
countries.push(responses[i][0][0].nativeName)
}
$('#countries').text(countries);
}
getCountryCapitals()
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<h4>Capital Cities : </h4> <span id="capitals"></span>
<h4>Respective Country's Native Names : </h4> <span id="countries"></span>
</div>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-18 22:03:56
Jako prosta alternatywa, która nie wymaga $.when.apply
ani array
, możesz użyć następującego wzoru do wygenerowania pojedynczej obietnicy dla wielu równoległych obietnic:
promise = $.when(promise, anotherPromise);
Np.
function GetSomeDeferredStuff() {
// Start with an empty resolved promise (or undefined does the same!)
var promise;
var i = 1;
for (i = 1; i <= 5; i++) {
var count = i;
promise = $.when(promise,
$.ajax({
type: "POST",
url: '/echo/html/',
data: {
html: "<p>Task #" + count + " complete.",
delay: count / 2
},
success: function (data) {
$("div").append(data);
}
}));
}
return promise;
}
$(function () {
$("a").click(function () {
var promise = GetSomeDeferredStuff();
promise.then(function () {
$("div").append("<p>All done!</p>");
});
});
});
Uwagi:
- domyśliłem się tego po zobaczeniu kogoś łańcuch obietnic sekwencyjnie, używając
promise = promise.then(newpromise)
- minusem jest to, że tworzy dodatkowe obiekty obietnicy za kulisami, a wszelkie parametry przekazywane na końcu nie są zbyt użyteczne (ponieważ są zagnieżdżone wewnątrz dodatkowych obiektów obiektów). Za to, co chcesz, choć jest krótki i prosty.
- plusem jest to, że nie wymaga zarządzania tablicami ani tablicami.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-12 10:20:12
Chcę zaproponować inny z użyciem $."każdy": {]}
-
Możemy zadeklarować funkcję ajax w postaci:
function ajaxFn(someData) { this.someData = someData; var that = this; return function () { var promise = $.Deferred(); $.ajax({ method: "POST", url: "url", data: that.someData, success: function(data) { promise.resolve(data); }, error: function(data) { promise.reject(data); } }) return promise; } }
-
Część kodu, w której tworzymy tablicę funkcji z Ajaxem do wysłania:
var arrayOfFn = []; for (var i = 0; i < someDataArray.length; i++) { var ajaxFnForArray = new ajaxFn(someDataArray[i]); arrayOfFn.push(ajaxFnForArray); }
-
I wywołanie funkcji z wysłaniem ajax:
$.when( $.each(arrayOfFn, function(index, value) { value.call() }) ).then(function() { alert("Cheer!"); } )
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-27 06:51:11
Jeśli transpilujesz i masz dostęp do ES6, możesz użyć składni spread, która specjalnie stosuje każdy iterowalny element obiektu jako dyskretny argument, dokładnie tak, jak potrzebuje tego $.when()
.
$.when(...deferreds).done(() => {
// do stuff
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-19 21:05:31
Jeśli używasz angularJS lub jakiegoś wariantu Biblioteki Q promise, to masz metodę .all()
, która rozwiązuje dokładnie ten problem.
var savePromises = [];
angular.forEach(models, function(model){
savePromises.push(
model.saveToServer()
)
});
$q.all(savePromises).then(
function success(results){...},
function failed(results){...}
);
Zobacz pełne API:
Https://github.com/kriskowal/q/wiki/API-Reference#promiseall
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-01 04:51:15
Miałem bardzo podobny przypadek, w którym umieszczałem w każdej pętli, a następnie ustawiałem znaczniki html w niektórych polach z liczb otrzymanych z ajax. Następnie musiałem zrobić sumę (teraz zaktualizowanych) wartości tych pól i umieścić w całkowitym polu.
Tak więc problem polegał na tym, że próbowałem zrobić sumę na wszystkich numerach, ale żadne dane nie wróciły jeszcze z połączeń async ajax. Musiałem uzupełnić tę funkcjonalność w kilku funkcjach, aby móc ponownie użyć kodu. Moje zewnętrzne funkcja czeka na dane, zanim pójdę i zrobię kilka rzeczy z w pełni zaktualizowanym DOM.
// 1st
function Outer() {
var deferreds = GetAllData();
$.when.apply($, deferreds).done(function () {
// now you can do whatever you want with the updated page
});
}
// 2nd
function GetAllData() {
var deferreds = [];
$('.calculatedField').each(function (data) {
deferreds.push(GetIndividualData($(this)));
});
return deferreds;
}
// 3rd
function GetIndividualData(item) {
var def = new $.Deferred();
$.post('@Url.Action("GetData")', function (data) {
item.html(data.valueFromAjax);
def.resolve(data);
});
return def;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-28 10:22:13