2012-07-18 26 views
13

mam prosty łańcuch zdarzeń:Chain jQuery Promises

  1. Get kolumny z tabeli metadanych (asynchronicznej)
  2. obciążenia wybranych kolumn (asynchroniczny)
  3. renderowania lista

Używałem po prostu łańcucha tych funkcji, każde z nich wywoływało następne, gdy zostało zakończone. Jednak nie jest to bardzo oczywiste, co się dzieje (wywołanie getColumnsFromMeta powoduje zapełnienie widoku). Dlatego w celu zachowania przejrzystości i ponownego użycia kodu chciałbym je poprawić za pomocą JQueryPromises. Używałem już obietnic. Ale w jaki sposób mogę połączyć więcej niż dwa? getColumnsFromMeta().then(loadSourceFromDatabase /*some arguments*/) //.then(renderList)?;

Oto przykład z getColumnsFromMeta:

var getColumnsFromMeta = function(id) 
{ 
    var sql, 
     dfd; 

    dfd = $.Deferred(); 

    var onSuccess = function(tx, result) 
    { 
     var columns = []; 

     for (var i = 0; i < result.rows.length; i++) 
     { 
      columns.push(result.rows.item(i).Column); 
     } 

     dfd.resolve(columns); 
    }; 

    var onError = function(tx, error) 
    { 
     dfd.reject(error); 
    }; 

    sql = "SELECT Column FROM Meta WHERE id = ?"; 

    database.query(sql, [id], onSuccess, onError); 

    return dfd.promise(); 
}; 

Odpowiedz

27

To powinno być coś takiego:

function getColumnsFromMeta() 
{ 
    var d = $.Deferred(); 

    // retrieve data in async manner and perform 
    // d.resolve(columns); 

    return d.promise(); 
} 

function loadSelectedColumns(columns) 
{ 
    var d = $.Deferred(); 

    // retrieve data in async manner and perform 
    // d.resolve(data); 

    return d.promise(); 
} 

function render(data) 
{ 
    // render your data 
} 

getColumnsFromMeta().pipe(loadSelectedColumns).pipe(render); 

http://jsfiddle.net/zerkms/xYDbm/1/ - oto próbka robocza

http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/ - jest to artykuł Bardzo podoba mi się obietnice

+0

Dzięki za szybką odpowiedź działa świetnie! I dzięki za artykuł, wygląda dobrze. Jako dodatkowe pytanie: czy można łączyć łańcuchy/etc, etc na rurze na różnych etapach? – JonWells

+0

@CrimsonChin: tak. PS: daj mi sekundę, jsfiddle zostanie zrobione za chwilę – zerkms

+0

@CrimsonChin: tak, możesz użyć dowolnego z nich, dopóki zwróci się również 'pipe()'. PS: Dodałem przykład jsfiddle – zerkms

4

Odpowiedź zerkms pomógł mi po chwili namysłu. Zamierzam opublikować to, co zrobiłem tutaj, na wypadek, gdyby pomocny był przykład z pełnym kontekstem.

/** 
* takes a list of componentIDs to load, relative to componentRoot 
* returns a promise to the map of (ComponentID -> componentCfg) 
*/ 
function asyncLoadComponents (componentRoot, components) { 

    var componentCfgs = {}; 

    function asyncLoadComponentCfg(component) { 
     var url = _.sprintf("%s/%s", componentRoot, component); 
     var promise = util.getJSON(url); 
     promise.done(function(data) { 
      componentCfgs[component] = data; 
     }); 
     return promise; 
    } 

    var promises = _.map(components, asyncLoadComponentCfg); 
    var flattenedPromise = $.when.apply(null, promises); 
    var componentCfgPromise = flattenedPromise.pipe(function() { 
     // componentCfgs is loaded now 
     return $.Deferred().resolve(componentCfgs).promise(); 
    }); 

    return componentCfgPromise; 
} 


var locale = 'en-US'; 
var componentRoot = '/api/components'; 
var components = ['facets', 'header', 'DocumentList']; 
$.when(asyncLoadComponents(componentRoot, components)).done(function(componentCfgs) { 
    buildDocumentListPage(locale, componentCfgs) 
});