Цепочка обещаний Jquery

У меня есть простая цепочка событий:

  1. Получить столбцы из таблицы метаданных (асинхронно)
  2. загрузить выбранные столбцы (асинхронно)
  3. список рендеринга

Раньше я просто связывал эти функции в цепочку, каждая из которых вызывала следующую после завершения. Однако не очень очевидно, что происходит (вызов getColumnsFromMeta приводит к заполнению представления). Итак, в интересах ясности и повторного использования кода я хотел бы реорганизовать их, используя JQuery Promises. Я использовал промисы раньше. Но как связать больше двух? getColumnsFromMeta ().then(loadSourceFromDatabase /*some arguments*/) //.then(renderList)?;

Вот пример 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();
};

person Jon Wells    schedule 18.07.2012    source источник


Ответы (2)


Это должно быть что-то вроде:

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/ — вот рабочий образец

http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/ -- это статья о промисах, которая мне очень нравится.

person zerkms    schedule 18.07.2012
comment
Спасибо за быстрый ответ, работает отлично! А за статью спасибо, выглядит хорошо. В качестве дополнительного вопроса: можно ли связать .done/.always и т. д. с трубой на разных этапах? - person Jon Wells; 18.07.2012
comment
@CrimsonChin: да. PS: дайте мне секунду, jsfiddle будет готов через мгновение - person zerkms; 18.07.2012
comment
@CrimsonChin: да, вы можете использовать любой из них, если pipe() также возвращает отложенный результат. PS: я добавил пример jsfiddle - person zerkms; 18.07.2012
comment
@pcv: не прошло и года, как я ответил на этот вопрос - person zerkms; 22.05.2013
comment
В jQuery 1.8 и более поздних версиях вы можете заменить «pipe» на «then», как правильно указано @pcv. - person Pulak Kanti Bhattacharyya; 02.08.2014
comment
@zerkms: Нет, но, поскольку ваш ответ по-прежнему является принятым, было бы полезно, если бы вы его обновили. - person Michael Scheper; 07.01.2015

Ответ zerkms помог мне после некоторых размышлений. Я собираюсь опубликовать то, что я сделал здесь, если пример с полным контекстом будет полезен.

/**
 * 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)
});
person Dustin Getz    schedule 16.04.2013