使用jQuery加载promises

时间:2011-06-28 13:26:26

标签: jquery jquery-deferred jquery-load promise

我仍然试图绕过deferred而不是,但是考虑到这一点,我有一个关于如何做以下事情的问题。

我的团队和我有3个单独的.load()方法,每个方法都抓取一个特定的模板并将其附加到同一个容器中。每个负载都会花费不同的时间,因此当内容加载时,它会以“阶梯式”方式加载(1,然后是2,然后是3)。我想使用deferred objects并等待它们全部完成,然后同时附加它们以移除“阶梯”动作。

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

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

所有三个电话都与上面的电话类似。

我怎样才能做到这一点?

5 个答案:

答案 0 :(得分:8)

我在这种情况下使用下一个代码:

$.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");
});

在我看来,它看起来比以前的实现更结构化,更漂亮。

答案 1 :(得分:6)

您可以将promise objects存储在数组中,然后使用$.when()查看这些承诺是否已满。这看起来像这样:

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/


更新

正如Alnitak指出的那样,如果没有“成功”回调处理程序,上面的例子就没有多大意义。如果在您使用.load()传输数据后触发“全部完成”处理程序就足够了,您只需要.resolve()来自success handler .load()中的承诺{{1}} 。这有什么意义吗?

答案 2 :(得分:4)

$.load()并非设计用于Deferred对象,也专门用于立即将内容放入页面。

要解决后一个问题,您必须将整个容器渲染到DOM之外,然后在完成后将其放入,或者您需要累积三个结果然后将它们全部放在一起。

以下流程使用后一种方法:

  1. 改为使用$.get(),并创建由jqXHR

  2. 返回的$.get()个对象的数组
  3. 将每个$.get()的返回片段存储在数组中

  4. 使用$.when.apply($, myArray).done(function() { ... })应用模板并将其放入DOM中

  5. 请参阅http://jsfiddle.net/alnitak/WW3ja/

答案 3 :(得分:2)

我使用以下代码作为通用库

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());
});

答案 4 :(得分:1)

Here's a Gist 一个小jQuery插件,它将loadThen函数添加到一组jQuery元素中。它基本上没有回调的load(),并且它返回一个仅在加载内容并插入所选元素集后才能解析的promise。

它基本上是jQuery自己的load()代码的复制/粘贴,除了它从实际的ajax调用返回promise。如果ajax失败,这可以让你获得被拒绝的承诺。

由于它基于load()功能,因此您可以在空格分隔的url之后添加一个选择器,以仅获取已加载的html的片段。


示例1:将此网站的主页加载到ID =&#34;容器&#34;

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

示例2 :将主页标题加载到此页面标题

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

要点内容:

(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));