2012-11-30 9 views
16

Biorąc pod uwagę te funkcje:Jak łańcuch ciągów funkcji odroczonych w jQuery 1.8.x?

function func1() { 
    var dfd = $.Deferred(); 

    setTimeout(function() { 
    dfd.resolve('Password'); 
    }, 1000); 

    return dfd.promise(); 
} 

function func2(message) { 
    var dfd = $.Deferred(); 

    setTimeout(function() { 
    if (message == 'Password') { 
     dfd.resolve('Hello World'); 
    } 
    }, 1000); 

    return dfd.promise(); 
} 

chciałbym znaleźć lepszy sposób, aby wykonać następujące czynności. Zauważ, że używa jQuery 1.8.x.

var promise = func1(); 

promise.done(function(message1) { 

    var promise2 = func2(message1); 

    promise2.done(function(message2) { 
    alert(message2); 
    }); 
}); 

Wszelkie pomysły? Myślałem, że używanie jQuery #pipe lub #then będzie działać, ale nie mogę tego rozgryźć. Oto skrzypce do zabawy: http://jsfiddle.net/Z7prn/

Odpowiedz

34

To nie jest takie skomplikowane (albo użyj .then lub .pipe, oba są takie same, ponieważ wydaje mi się, że jQuery 1.8).

promise.then(func2).done(function(message) { 
    alert(message); 
}); 

Od func2 Zwraca nowy odroczony obiektu, .done zwrotna jest dołączony do tego jeden zamiast.

DEMO

+1

Uwielbiam, gdy ludzie wyjaśniają rzeczy w taki sposób zwięzły. łatwiejsze do zrozumienia i śledzenia – tim

+1

Uwaga: Należy używać '.then', ponieważ' .pipe' jest przestarzałe w jQuery 1.8 ([docs] (http://api.jquery.com/deferred.pipe/)) – nhylated

-2

Zastosowanie JQuery.when(). Dokładnie to, co chcesz połączyć z łańcuchem odroczeń i uruchomić funkcję, gdy wszystkie są zakończone.

Aktualizacja 2017 (po obejrzeniu downvotes):

Co PO chciała była lepsza wersja jego uruchomienie kodu obietnic sekwencyjnie. Oto moja wersja użyciu $.when:

function func1() { 
 
    var dfd = $.Deferred(); 
 

 
    setTimeout(function() { 
 
    dfd.resolve('Password'); 
 
    }, 1000); 
 

 
    return dfd.promise(); 
 
} 
 

 
function func2(message) { 
 
    var dfd = $.Deferred(); 
 

 
    setTimeout(function() { 
 
    if (message == 'Password') { 
 
     dfd.resolve('Hello World'); 
 
    } 
 
    }, 1000); 
 

 
    return dfd.promise(); 
 
} 
 

 
// ~~~~~~~~~~ using $.when here ~~~~~~~~~~~~ 
 

 
$.when(func1()).then(function(result1) { 
 
    $.when(func2(result1)).then(function(result2) { 
 
     alert(result2); 
 
    }) 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>

+5

Nie są one przykuty - są zbierane. Tablica defersów jest uruchamiana "od razu", a callback zwrotny when() jest uruchamiany, gdy wszystkie są zakończone. wtedy(), z drugiej strony, może być połączony, więc func1() musi zostać rozwiązane przed func2() itp. –

+0

@DesignbyAdrian Dlaczego interpretujesz pytanie OP w inny sposób ?! Możesz uruchomić swój opublikowany kod lub przeczytać tytuł i zobaczyć, że on * chce *, aby jechać. Po prostu szuka sposobu na przepisanie drugiego snipped przy użyciu lepszego sposobu i to jest to, o czym wspomniałem i właśnie dodałem przykład. Wydajność mojego fragmentu jest taka sama jak jego (tak jak chciał) w 3 LOC. – Aidin

5

miałem podobny przypadek użycia, więc myślę, że to powinno pomóc.

Następująca metoda wymaga użycia szeregu metod (które mogą lub nie mogą zwrócić obietnice) i wykonania ich w sekwencji, czekając aż każdy odroczony zostanie ukończony przed kontynuowaniem. Domyślnym zachowaniem jest zatrzymanie się po awarii; drugi argument pozwala ci kontynuować, czy wywołanie się nie powiedzie, czy nie.

zrobić/fail podpisy Wózek są (Array < kontekst>) Funkcja (Array < Object {odrzucone | rozwiązane: argumenty}>), gdzie kontekst jest kontekst każdego resolveWith rozmowy/rejectWith lub odroczony, a argumenty to zestaw argumentów, który został przyjęty w rozdzielczości/odrzuceniu.

(function ($) { 
    "use strict"; 
    var copy = function (a) { 
     return Array.prototype.slice.call(a); 
    }; 

    /** 
     Handle a sequence of methods, stopping on failure by default 
     @param Array<Function> chain List of methods to execute. Non-deferred return values will be treated as successful deferreds. 
     @param Boolean continueOnFailure Continue executing even if one of the returned deferreds fails. 
     @returns Deferred 
    */ 
    $.sequence = function (chain, continueOnFailure) { 
     var handleStep, handleResult, 
      steps = copy(chain), 
      def = new $.Deferred(), 
      defs = [], 
      results = []; 
     handleStep = function() { 
      if (!steps.length) { 
       def.resolveWith(defs, [ results ]); 
       return; 
      } 
      var step = steps.shift(), 
       result = step(); 
      handleResult(
       $.when(result).always(function() { 
        defs.push(this); 
       }).done(function() { 
        results.push({ resolved: copy(arguments) }); 
       }).fail(function() { 
        results.push({ rejected: copy(arguments) }); 
       }) 
      ); 
     }; 
     handleResult = continueOnFailure ? 
       function (result) { 
        result.always(function() { 
         handleStep(); 
        }); 
       } : 
       function (result) { 
        result.done(handleStep) 
         .fail(function() { 
          def.rejectWith(defs, [ results ]); 
         }); 
       }; 
     handleStep(); 
     return def.promise(); 
    }; 
}(this.jQuery)); 

Prosty przykład użycia: http://jsfiddle.net/rG9rA/

function func1() { 
    var dfd = $.Deferred(); 

    setTimeout(function() { 
    dfd.resolve('Password'); 
    }, 1000); 

    return dfd.promise(); 
} 

function func2(message) { 
    var dfd = $.Deferred(); 

    setTimeout(function() { 
    if (message == 'Password') { 
     dfd.resolve('Hello World'); 
    } 
    }, 1000); 

    return dfd.promise(); 
} 

    $.sequence([func1, func2, function() { alert('done'); }]); 
+0

Nice. Dodałem opcjonalne "opóźnienie" między połączeniami, na wypadek, gdyby jakiś zewnętrzny kod wymagał rozstrzygnięcia zdarzeń (używam Knockout) –

Powiązane problemy