2011-11-08 14 views
11

Mam aplikację internetową, która musi wielokrotnie wywoływać serwer. Do tej pory miałem długi zagnieżdżony łańcuch wywołań zwrotnych; ale chciałbym użyć funkcjonalności jQuery: when, then itd. Jednak nie mogę sprawić, że rzeczy znowu będą działały po użyciu then.Łańcuchy żądań ajax z jQuery odroczone

$ 
.when ($.get('pages/run-tool.html')) 
.then (function (args) 
{ 
    // This works fine 
    alert(args); 
    $('#content').replaceWith (args); 
    $('#progress-bar').progressbar ({value: 0}); 
}) 
.then ($.get('pages/test.html')) 
.done (function(args) 
{ 
    // This prints the same as the last call 
    alert (args); 
}); 

Co robię źle? Zgaduję, że jest to problem z określaniem zakresu, ponieważ widzę, że drugie wywołanie get jest wykonywane. Używanie dwóch różnych zmiennych args nie pomaga, ponieważ argument przekazany do wykonanej funkcji jest wciąż pierwszym żądaniem.

Odpowiedz

29

jako aktualizacja:

Z nowoczesnych jQuery (1.8+) nie trzeba wstępna gdy ponieważ dostać zwraca odroczony obietnicy.

Ponadto, rurka jest przestarzała. Zamiast tego użyj , a następnie. Tylko pamiętaj, aby zwrócić wynik nowego otrzymania, który staje się Obietnicą dołączoną późniejszymi , a następnie/* done */nieudanych połączeń.

Więc:

$.get('pages/run-tool.html') 
.then (function (args) { // this will run if the above .get succeeds 
    // This works fine 
    alert(args); 
    $('#content').replaceWith (args); 
    $('#progress-bar').progressbar ({value: 0}); 
}) 
.then (function() { // this will run after the above then-handler (assuming it ran) 
    return $.get('pages/test.html'); // the return value creates a new Deferred object 
}) 
.done (function(args) { // this will run after the second .get succeeds (assuming it ran) 
    alert (args); 
}); 
12

Wszystkie trzy wywołania zwrotne (dwie z then i jedna z done) są stosowane do tego samego żądania - oryginalnego wywołania when. Dzieje się tak, ponieważ then zwraca ten sam obiekt Odroczony zamiast nowego, aby można było dodać wiele procedur obsługi zdarzeń.

Zamiast tego należy użyć pipe.

$ 
.when ($.get('pages/run-tool.html')) 
.then (function (args) 
{ 
    // This works fine 
    alert(args); 
    $('#content').replaceWith (args); 
    $('#progress-bar').progressbar ({value: 0}); 
}) 
.pipe (function() { 
    return $.get('pages/test.html'); // the return value creates a new Deferred object 
}) 
.done (function(args) 
{ 
    alert (args); 
}); 
+0

Dzięki, to działa! Zaakceptuję, gdy tylko stackoverflow pozwoli mi :) – Anteru

+0

Łańcuchowanie jQuery wciąż wygląda dla mnie okropnie – PHearst

+1

@phearst Zwróć uwagę, że ta metoda jest teraz przestarzała. – lonesomeday

-2

Moim sposobem jest zastosowanie funkcji oddzwaniania:

A(function(){ 
     B(function(){ 
      C()})}); 

gdzie A, B mogą być zapisywane jako

function A(callback) 
$.ajax{ 
    ... 
    success: function(result){ 
     ... 
     if (callback) callback(); 
    } 
} 
+3

Nie używa to jednak opóźnień jQuery i jest podatna na "efekt piramidy" (nieograniczone zagnieżdżanie powodujące duże wcięcie). Sądzę, że właśnie tego próbował uniknąć. –

1

Tutaj jest cudownie proste i wysoce efektywna wtyczka do łączenia/kolejkowania AJAX. Wykona cię metody ajax w kolejności jeden po drugim.

Działa poprzez akceptację szeregu metod, a następnie wykonanie ich kolejno. Nie będzie wykonywać kolejnej metody podczas oczekiwania na odpowiedź.

// --- Ta część jest kodzie -----------------------

$ (document). gotowy (funkcja() {

var AjaxQ = []; 
AjaxQ[0] = function() { AjaxMethod1(); } 
AjaxQ[1] = function() { AjaxMethod2(); } 
AjaxQ[3] = function() { AjaxMethod3(); } 

//Execute methods in sequence 
$(document).sc_ExecuteAjaxQ({ fx: AjaxQ }); 

});

// --- Ta część jest Ajax PLUGIN -------------------

$ .fn.sc_ExecuteAjaxQ = function (opcje) {

//? Executes a series of AJAX methods in dequence 

var options = $.extend({ 

    fx: [] //function1() { }, function2() { }, function3() { } 

}, options); 

if (options.fx.length > 0) { 

    var i = 0; 

    $(this).unbind('ajaxComplete'); 
    $(this).ajaxComplete(function() { 

     i++; 
     if (i < options.fx.length && (typeof options.fx[i] == "function")) { options.fx[i](); } 
     else { $(this).unbind('ajaxComplete'); } 

    }); 

    //Execute first item in queue 
    if (typeof options.fx[i] == "function") { options.fx[i](); } 
    else { $(this).unbind('ajaxComplete'); } 

} 

}

0
<script type="text/javascript"> 

    var promise1 = function() { 
     return new 
     $.Deferred(function (def) { 
      setTimeout(function() { 
       console.log("1"); 
       def.resolve(); 
      }, 3000); 
     }).promise(); 
    }; 

    var promise2 = function() { 
     return new 
     $.Deferred(function (def) { 
      setTimeout(function() { 
       console.log("2"); 
       def.resolve(); 
      }, 2000); 
     }).promise(); 
    }; 

    var promise3 = function() { 
     return new 
     $.Deferred(function (def) { 
      setTimeout(function() { 
       console.log("3"); 
       def.resolve(); 
      }, 1000); 
     }).promise(); 
    }; 

    var firstCall = function() { 
     console.log("firstCall"); 
     $.when(promise1()) 
     .then(function() { secondCall(); }); 
    }; 

    var secondCall = function() { 
     console.log("secondCall") 
     $.when(promise2()).then(function() { thirdCall(); }); 
    }; 

    var thirdCall = function() { 
     console.log("thirdCall") 
     $.when(promise3()).then(function() { console.log("done"); }); 
    }; 


    $(document).ready(function() { 
     firstCall(); 
    }); 
</script> 
0

myślałem, że chciałbym zostawić ten mały ćwiczenia tutaj dla każdego, kto może się przydać, budujemy tablicę wniosków i kiedy są zakończone, możemy wywołać funkcję zwrotną:

var urls = [{ 
    url: 'url1', 
    data: 'foo' 
}, { 
    url: 'url2', 
    data: 'foo' 
}, { 
    url: 'url3', 
    data: 'foo' 
}, { 
    url: 'url4', 
    data: 'foo' 
}]; 
var requests = []; 
var callback = function (result) { 
    console.log('done!'); 
}; 

var ajaxFunction = function() { 
    for (var request, i = -1; request = urls[++i];) { 
     requests.push($.ajax({ 
      url: request.url, 
      success: function (response) { 
       console.log('success', response); 
      } 
     })); 
    } 
}; 

// using $.when.apply() we can execute a function when all the requests 
// in the array have completed 
$.when.apply(new ajaxFunction(), requests).done(function (result) { 
    callback(result) 
}); 
1

Odpowiedź cdr, która ma najwyższy wynik w tej chwili, jest nieprawidłowa.

Kiedy masz funkcje a, b, c każdy zwraca $ .Deferred() obiektu, łańcuchy i funkcje, takie jak następujące:

a().then(b).then(c) 

Zarówno bic będzie działać, gdy wróciłam z obietnicą został rozwiązany. Ponieważ zarówno wtedy (funkcje) są związane z obietnicą, to działa podobna do innych Jquery łączenia takich jak:

$('#id').html("<div>hello</div>").css({display:"block"}) 

gdzie zarówno html() i css function() są nazywane na obiekt wrócił z $ ('#ID');

więc zrobić, b, c bieg po obietnicy powróciła z poprzedniej funkcji zostanie rozwiązany, trzeba to zrobić:

a().then(function(){ 
    b().then(c) 
}); 

Tutaj wywołanie funkcji C jest związany z obietnicą wrócił z funkcja b.

Można to sprawdzić za pomocą następującego kodu:

function a() { 
    var promise = $.Deferred(); 
    setTimeout(function() { 
     promise.resolve(); 
     console.log("a"); 
    }, 1000); 
    return promise; 
} 

function b() { 
    console.log("running b"); 
    var promise = $.Deferred(); 
    setTimeout(function() { 
     promise.resolve(); 
     console.log("b"); 
    }, 500); 
    return promise; 
} 

function c() { 
    console.log("running c"); 
    var promise = $.Deferred(); 
    setTimeout(function() { 
     promise.resolve(); 
     console.log("c"); 
    }, 1500); 
    return promise; 
} 

a().then(b).then(c); 
a().then(function(){ 
    b().then(c) 
}); 

Zmień obietnica w funkcji B() z determinacją(), aby odrzucić(), a zobaczysz różnicę.

+0

Odpowiedź cdr jest właściwa. Sprawdź ten skrzypiec http://jsfiddle.net/0pb0g70y/ wykonanym kodem, z pewnymi zmianami dla jasności. 'c' nie jest wywoływane, dopóki' b' nie zostanie zakończone. Drugie "wtedy" nie dotyczy obietnicy "a", ale obietnicy zwróconej przez 'b' (jeśli zwraca obietnicę, co ma miejsce w twoim przykładzie, oraz w odpowiedzi cdr na jej drugie' to') . –

Powiązane problemy