我们在单页面应用程序中使用JQuery。 我们的boostrapper是应用程序的起点,看起来像这样:
define('homebootstrapper',
['jquery', 'config', 'homerouteconfig', 'presenter', 'dataprimer', 'binder'],
function ($, config, homeRouteConfig, presenter, dataprimer, binder) {
var
run = function () {
$('#busyIndicator').activity(true);
$.when(dataprimer.fetch())
.done(function () {
// $('#busyIndicator').activity(false);
});
};
return {
run: run
};
});
被调用的数据驱动程序如下所示:
define('dataprimer',
['ko', 'datacontext', 'config'],
function (ko, datacontext, config) {
var logger = config.logger,
fetch = function () {
return $.Deferred(function (def) {
console.log('in deferred');
$.when(LongTimeProcessing())
.pipe(function () {
logger.success('Fetched data');
})
.fail(function () { def.reject(); })
.done(function () { def.resolve(); });
}).promise();
};
return {
fetch: fetch
};
});
function LongTimeProcessing(options) {
console.log('in when');
return $.Deferred(function (def) {
var results = options;
for (var i = 0; i < 10; i++) {
var x = i;
$('#counter').html(x);
}
def.resolve(results);
}).promise();
}
第$('#busyIndicator').activity(true);
行
应该显示基于SVG或VML的进度动画。除了使用JQuery $ .when
使用此示例代码,我们尝试创建一个需要一些时间的方法,称为“LongTimeProcessing”(而不是通常通过放大使用的后端的ajax调用)
我们看到当我们使用jquery时,busyindicator不起作用(读取:不显示),直到dataprimer返回def.resolve()。这时似乎阻止了所有UI更新。此外,LongTimeProcessing方法的计数器值仅显示此循环的最后一个值。它被执行但它永远不可见。
我们做错了什么?我们该如何应对呢?
答案 0 :(得分:3)
你必须屈服于事件处理循环,以允许UI更新和处理未完成的事件。只有在您自己的代码执行完毕后才会发生这种情况。
您的LongTimeProcessing
函数不会执行此操作,它会启动一个循环并且不会将控制权返回给浏览器,直到该循环结束。
您可以使用setTimeout
来处理循环迭代,从而实现您想要的目标:
function LongTimeProcessing(options) {
console.log('in when');
return $.Deferred(function (def) {
var results = options;
var i = 0;
(function iterate() {
$('#counter').html(i);
if (i < 10) {
++i;
setTimeout(iterate, 250);
} else {
def.resolve(results);
}
})();
}).promise();
}
对setTimeout
的调用允许函数在第一次调用iterate()
后立即终止,允许浏览器的事件处理循环处理UI更新,然后进入下一次迭代当计时器过去时。