我仍然试图绕过deferred
而不是,但是考虑到这一点,我有一个关于如何做以下事情的问题。
我的团队和我有3个单独的.load()
方法,每个方法都抓取一个特定的模板并将其附加到同一个容器中。每个负载都会花费不同的时间,因此当内容加载时,它会以“阶梯式”方式加载(1,然后是2,然后是3)。我想使用deferred
objects并等待它们全部完成,然后同时附加它们以移除“阶梯”动作。
$('<div>').load(baseInfoTemplate, function () {
var baseData = {
// build some object
};
$.tmpl(this, baseData).appendTo($generalContainer);
});
所有三个电话都与上面的电话类似。
我怎样才能做到这一点?
答案 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之外,然后在完成后将其放入,或者您需要累积三个结果然后将它们全部放在一起。
以下流程使用后一种方法:
改为使用$.get()
,并创建由jqXHR
$.get()
个对象的数组
将每个$.get()
的返回片段存储在数组中
使用$.when.apply($, myArray).done(function() { ... })
应用模板并将其放入DOM中
答案 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));