2012-11-30 7 views
16

Attribuite queste funzioni:Come concatenare una sequenza di funzioni differite in 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(); 
} 

mi piacerebbe trovare un modo migliore per fare quanto segue. Nota, si sta usando jQuery 1.8.x.

var promise = func1(); 

promise.done(function(message1) { 

    var promise2 = func2(message1); 

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

Qualche idea? Pensavo che usare jQuery #pipe o #questi funzionasse, ma non riesco a capirlo. Ecco un violino per giocare: http://jsfiddle.net/Z7prn/

risposta

34

Non è così complicato (o utilizzare .then o .pipe, sono entrambi gli stessi da jQuery 1.8 Penso).

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

Da func2 restituisce un nuovo oggetto differita, il .done callback è collegata a quella invece.

DEMO

+1

Mi piace quando le persone spiegano le cose in maniera concisa. più semplice da comprendere e seguire – tim

+1

Nota: utilizzare '.then' poiché' .pipe' è stato deprecato in jQuery 1.8 ([docs] (http://api.jquery.com/deferred.pipe/)) – nhylated

-2

Usa JQuery.when(). È esattamente ciò che si desidera concatenare una serie di differimenti ed eseguire una funzione al termine di tutti.

Aggiornamento 2017 (dopo aver visto downvotes):

Cosa OP voleva era una versione migliore del suo codice per eseguire le promesse in modo sequenziale. Ecco la mia versione utilizzando $.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

Non sono incatenato - sono raccolti. L'array di defers viene sparato 'alla volta', e il callback (quando) viene lanciato con tutti gli eventi. quindi(), d'altra parte, può essere concatenato in modo che func1() debba essere risolto prima di func2() ecc. –

+0

@DesignbyAdrian Perché interpretate la domanda dell'OP in modo diverso ?! Puoi eseguire il codice postato o leggere il titolo e vedere che * vuole * chiamarli con _chain_. Sta solo cercando un modo per riscrivere il secondo tagliato usando un modo migliore e questo è quello che ho citato e appena aggiunto un esempio. L'output di My snippet è uguale al suo (come voleva) in 3 LOC. – Aidin

5

ho avuto un caso simile uso, quindi penso che questo dovrebbe aiutare.

Il seguente metodo impiegherà una serie di metodi (che possono o non possono restituire Promises) ed eseguirli in sequenza, in attesa che ogni differimento sia completo prima di procedere. Il comportamento predefinito è di fermarsi in caso di fallimento; secondo argomento ti consente di continuare se la chiamata fallisce o meno.

fatto/non riescono firme handler sono (Array < contesto>) Funzione (Array < Object {respinti | risolti: argomenti}>), in cui contesto è il contesto di ogni chiamata/rejectWith resolveWith, o il differito in questione e gli argomenti sono gli argomenti impostati nella risoluzione/rifiuto.

(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)); 

Un semplice esempio di utilizzo: 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

Bello. Ho aggiunto un "ritardo" opzionale tra le chiamate, nel caso in cui alcuni codici esterni necessitino di eventi da regolare (utilizzo Knockout) –

Problemi correlati