2012-07-18 19 views
13

que tienen una simple cadena de acontecimientos:Cadena de Jquery Promises

  1. Obtener columnas de una tabla de metadatos (asíncrono)
  2. columnas de carga seleccionado (asíncrono)
  3. lista render

Solía ​​simplemente encadenar estas funciones, cada una llamando a la siguiente cuando se había completado. Sin embargo, no es muy obvio lo que está sucediendo (llamando al getColumnsFromMeta los resultados en la vista que se llena). Por lo tanto, en aras de la claridad y la reutilización del código, me gustaría refactorizarlos usando JQueryPromises. He usado promesas antes. ¿Pero cómo encadenar más de dos? getColumnsFromMeta().then(loadSourceFromDatabase /*some arguments*/) //.then(renderList)?;

Aquí hay un ejemplo de la 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(); 
}; 

Respuesta

27

Debería ser algo como:

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/ - Este es un ejemplo de trabajo

http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/ - este es el artículo Me encantan las promesas

+0

Gracias por la respuesta rápida que funciona de maravilla! Y gracias por el artículo, se ve bien. Como pregunta adicional: ¿es posible encadenar .done/.always, etc. a la tubería en diferentes etapas? – JonWells

+0

@CrimsonChin: sip. PD: dame un segundo, jsfiddle se hará en un momento – zerkms

+0

@CrimsonChin: sí, puedes usar cualquiera de ellos, siempre y cuando 'pipe()' también devuelva diferido. PD: He añadido jsfiddle ejemplo – zerkms

4

La respuesta de zerkms me ayudó después de pensarlo un poco. Voy a publicar lo que hice aquí en caso de que un ejemplo con contexto completo sea útil.

/** 
* 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) 
});