使用jQuery加载promises

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

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

 $('
').load(baseInfoTemplate, function () { var baseData = { // build some object }; $.tmpl(this, baseData).appendTo($generalContainer); });

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

我怎样才能做到这一点?

$.load()不是为与Deferred对象一起使用而设计的,它也专门用于立即将内容放入页面中。

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

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

  1. 改为使用$.get() ,并创建$.get()返回的jqXHR对象的数组

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

  3. 使用$.when.apply($, myArray).done(function() { ... })来应用模板并将它们放入DOM中

见http://jsfiddle.net/alnitak/WW3ja/

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

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

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

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

 var templates = [ ]; function createPromise( baseInfoTemplate ) { return $.Deferred(function( promise ) { $('
').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指出的那样,如果没有“成功”回调处理程序,上面的例子就没有多大意义。 如果在使用.resolve()传输数据之后触发“全部完成”处理程序就足够了,您只需要.resolve()来自.resolve()success handler的promise。 这有任何意义吗?

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

 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() { $( '
' ).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()); }); 

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

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

由于它基于load()function,因此您可以在空格分隔的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 }); 

要点内容:

 (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("
").append(jQuery.parseHTML(responseText)).find(selector) : responseText); return self; }); }; }(jQuery));