Chain of Jquery Promises

Jon Wells picture Jon Wells · Jul 18, 2012 · Viewed 12.8k times · Source

I have a simple chain of events:

  1. Get Columns from a metaData table (async)
  2. load selected columns (async)
  3. render list

I used to just the chain these functions, each calling the next when it had completed. However, its not very obvious what's going (calling getColumnsFromMeta results in the view being populated). So in the interest of clarity and code re-use I'd like to refactor these using JQuery Promises. I have used promises before. But how do I chain more than two? getColumnsFromMeta ().then(loadSourceFromDatabase /*some arguments*/) //.then(renderList)?;

Here's an example of the 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();
};

Answer

zerkms picture zerkms · Jul 18, 2012

It should be something like:

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/ - here is a working sample

http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/ -- this is the article I really like about promises