Подтвердить что ты не робот

Использование загрузки jQuery с помощью promises

Я все еще пытаюсь обернуть голову вокруг deferred, а что нет, поэтому, имея в виду, у меня есть вопрос о как сделать следующее.

У моей команды и у меня есть 3 отдельных метода .load(), которые каждый из них захватывает конкретный шаблон и добавляет его в тот же контейнер. Каждая нагрузка занимает различное количество времени, как вы могли бы подумать, поэтому, когда контент загружается, он загружается с шагом "ступеньки" (1, затем 2, затем 3). Я хотел бы использовать deferred objects и ждать, пока они все будут выполнены, затем добавьте их одновременно, чтобы удалить "шаг лестницы".

$('<div>').load(baseInfoTemplate, function () {
    var baseData = {
        // build some object
    };

    $.tmpl(this, baseData).appendTo($generalContainer);
});

Все три вызова похожи на вызов выше.

Как я могу это достичь?

4b9b3361

Ответ 1

$.load() не предназначен для использования с отложенными объектами, а также предназначен для немедленного удаления материала на страницу.

Чтобы решить эту последнюю проблему, вам либо нужно отобразить весь контейнер вне DOM, а затем отбросить его, когда все будет готово, или вам нужно аккумулировать три результата, а затем поместить их все за один раз.

В следующем процессе используется последний подход:

  • Вместо этого используйте $.get() и создайте массив объектов jqXHR, возвращаемых $.get()

  • Хранить возвратные фрагменты из каждого $.get() в массиве тоже

  • Используйте $.when.apply($, myArray).done(function() { ... }), чтобы применить шаблоны и поместить их в DOM

См. http://jsfiddle.net/alnitak/WW3ja/

Ответ 2

Я использую следующий код для этого случая:

$.when(
    $.get('templates/navbar.tmpl.html', function(data) {
        $('#navbar').html(data);
    }),
    $.get('templates/footer.tmpl.html', function(data) {
        $('#footer').html(data);
    }),
    $.Deferred(function(deferred) {
        $(deferred.resolve);
    })
).done(function() {
    $.getScript("js/tools/jquery.min.js");
});

На мой взгляд, он выглядит более структурированным и довольно приятным, чем предыдущие реализации.

Ответ 3

Вы можете сохранить promise objects в массиве и использовать $.when(), чтобы узнать, заполнены ли эти promises. Это может выглядеть так:

var templates = [ ];

function createPromise( baseInfoTemplate ) {
    return $.Deferred(function( promise ) {
        $('<div>').load(baseInfoTemplate, function() {
            var baseData = { /* foobar */ };

            templates.push( baseData );
            promise.resolve();
        });
    }).promise();
}

var myPromises = [ ];

myPromises.push( createPromise( 'some data' ) );
myPromises.push( createPromise( 'even moar data' ) );
myPromises.push( createPromise( 'foo bar heay' ) );

$.when.apply( null, myPromises ).done( function() {
    templates.forEach(function( template ) {
        $.tmpl(this, template).appendTo($generalContainer);
    });
});

Я использую .apply() здесь, потому что он принимает массив как аргументы для вызова функции. Итак, в основном, мы передаем все promises объекты в .when().

Пример: http://jsfiddle.net/Hg77A/1/


Update:

как указал Алнитак, приведенный выше пример не имеет большого смысла, если не существует обработчика обратного вызова "success". Если этого достаточно, чтобы запустить обработчик "все сделано" после передачи данных с помощью .load(), вам просто нужно .resolve() promises в success handler от .load(). Это имеет смысл?

Ответ 4

Я использую следующий код в качестве общей библиотеки

var loader = {};
(function(){
  var fn = {  
    promises: [],
    templates: [],

    loadTemplate: function( name ) {
      fn.promises.push(
        $.get( `templates/${name}.tmpl.html`,
               (html) => fn.templates.push( html )
        )
      );
    },

    main: function( templates, callback ) {
      templates.forEach( (template) => fn.loadTemplate( template ));
      $.when.apply( $, fn.promises ).done( function() {
        $( '<div id="templates">' ).html( fn.templates.join() ).appendTo( 'body' );
        callback();
      });
    }
  };

  /* EXPORTS */
  loader.main = fn.main;
})();

затем назовите его первой функцией в главном файле js приложения.

function myMain() {
  ... // do all the things
}

$( document ).ready( function() {
  templates = [ 'thingies', 'wotsits', 'oojamaflips' ];
  loader.main( templates, () => myMain());
});

Ответ 5

Здесь Gist для небольшого плагина jQuery, который добавляет функцию loadThen к набору элементов jQuery. Он в основном загружает() без обратного вызова и возвращает обещание, которое разрешается только после загрузки содержимого и вставки в набор выбранных элементов.

Это в основном копия/вставка кода jQuery собственного load(), за исключением того, что он возвращает обещание от фактического вызова ajax. Это позволяет получить отклоненное обещание, если ошибка ajax не удалась.

Поскольку он основан на функциональности load(), вы можете добавить селектор после URL, разделенного пробелом, чтобы получить только фрагмент загруженного html.


Пример 1: Загрузите домашнюю страницу этого сайта в элемент с id = "container"

$('#container').loadThen('/').then(function () {
    // loaded and ready.
}, function () {
    // error
});

Пример 2: Загрузите заголовок домашней страницы в этот заголовок страницы

$('h1').eq(0).loadThen('/ h1').then(function () {
    // loaded and ready.
}, function () {
    // error
});

Содержимое gist:

(function ($) {
    var _loadThen = $.fn.loadThen;
    $.fn.loadThen = function (url, params) {
        if (typeof url !== "string" && _loadThen) {
            return _loadThen.apply(this, arguments);
        }

        if(this.length <= 0) {
            return jQuery.Deferred().resolveWith(this, ['']);
        }

        var selector, type, response,
            self = this,
            off = url.indexOf(" ");

        if (off >= 0) {
            selector = jQuery.trim(url.slice(off));
            url = url.slice(0, off);
        }

        if (params && typeof params === "object") {
            type = "POST";
        }

        return jQuery.ajax({
            url: url,
            type: type,
            dataType: "html",
            data: params
        }).then(function (responseText) {
                self.html(selector ? jQuery("<div>").append(jQuery.parseHTML(responseText)).find(selector) : responseText);
            return self;
        });
    };
}(jQuery));