我有一个更新一些DOM元素的函数,然后使用setTimeout调用回调,如下所示(如果提供了一个 - 否则调用一个虚函数):
function updateprogressbar(id,val,label,callback) {
var time = 0;
if (typeof callback === "function") {
var func = callback;
} else {
var func = function () {};
}
$( "#progressbar" ).progressbar({
value: val
});
$( "#progress-label"+id ).html("Overall Progress: "+label);
setTimeout(func(),time);
}
使用此for循环调用:
for(var i=0;i<emails.length;i++) {
var howmuchdone = Math.ceil(totalchecked*100/totaltocheck);
updateprogressbar(1,howmuchdone,howmuchdone+"%",function () {
$("#EMAIL_ALL").val($("#EMAIL_ALL").val()+","+getmeadescriptor($.trim(emails[i])));
});
totalchecked = totalchecked + 1;
}
它正在正确执行它的回调,但我使用setTimeout的目的是确保浏览器呈现更新的DOM元素。由于我无法弄清楚的原因,DOM元素没有被更新。
(在for循环中调用updateprogressbar,并且传递给它的回调是一个匿名函数,它执行一些简单的处理 - 尽管我不认为这与此问题相关。)
关于为什么我没有在updateprogressbar调用上获得任何浏览器呈现的任何想法?
谢谢!
所以,按照@ vinhHT的评论,我会试试这个:
var testfunction = function (value) {
$("#EMAIL_ALL").val($("#EMAIL_ALL").val()+","+value;
}
for(var i=0;i<emails.length;i++) {
var howmuchdone = Math.ceil(totalchecked*100/totaltocheck);
updateprogressbar(1,howmuchdone,howmuchdone+"%",testfunction(getmeadescriptor($.trim(emails[i]))));
totalchecked = totalchecked + 1;
}
答案 0 :(得分:2)
在setTimeout中删除()
As setTimeout(func,time);
在jfriend00的评论之后编辑:
将函数正确声明为:
var func = function(){ //生意就在这里 }
在代码中更正对上述回调的调用
setTimeout(func,time);
3编辑问题已被编辑:在if-else块之外声明func,更正setTimeout调用
function updateprogressbar(id, val, label, callback) {
var time = 0;
var func;
if (typeof callback === "function") {
func = callback;
} else {
func = function() {};
}
$("#progressbar").progressbar({
value: val
});
$("#progress-label" + id).html("Overall Progress: " + label);
setTimeout(func, time);
}
答案 1 :(得分:0)
修改强>
现在,您已经公开了for
循环代码,我们可以看到,为了让循环的每个循环在下一个循环执行之前重新绘制,您需要开始循环的每个下一次迭代一个setTimeout()
。这允许代码返回循环执行之间的事件循环。你可以这样做:
// utility function to iterate a loop, but have a short `setTimeout()`
// pause between each loop iteration
// assumes mainFn is a synchronous operation
// doneFn is optional and, if present, will be called when all iterations are done
function iterateWithRepaint(start, num, incr, mainFn, doneFn){
var end = start + num;
function next() {
if (start < end) {
mainFn(start);
start += incr;
setTimeout(next, 20);
} else {
if (typeof doneFn === "function") {
doneFn();
}
}
}
next();
}
// got rid of callback in here since it was not helpful
// and added loop index as an argument
function updateprogressbar(id, val, label, i) {
var time = 0;
$( "#progressbar" ).progressbar({
value: val
});
$("#EMAIL_ALL").val($("#EMAIL_ALL").val()+","+getmeadescriptor($.trim(emails[i])));
$( "#progress-label"+id ).html("Overall Progress: "+label);
}
// call your function with a timer delay between each iteration
iterateWithRepaint(0, emails.length, 1, function(i) {
var howmuchdone = Math.ceil(totalchecked*100/totaltocheck);
updateprogressbar(1,howmuchdone,howmuchdone+"%", i);
totalchecked = totalchecked + 1;
});
有一些其他方法可以触发重排,有时通过请求某些CSS属性进行重新绘制,这些属性只能在完全重新布局后准确报告,以便浏览器强制重新布局,但这种方法已被证明是一个难以捉摸的移动目标因为为了提高性能,浏览器一直试图优化他们认为不必要的重绘。所以,我选择不依赖这些技术。
在循环代码披露之前的先前答案:
您的setTimeout()
声明不正确,但问题还不止于此。
即使正确声明,setTimeout()
本身也不允许您的网页引用。所做的就是安排一些代码在将来运行。相反,您必须立即停止运行代码并将未来的代码放入setTimeout
回调中。只有这样才能让当前线程返回事件循环,然后给屏幕重新绘制的机会。
仅供参考,您的setTimeout()
应该是这样的:
setTimeout(func,time);
但是在您显示的代码中更改它将无法解决任何问题,因为func()
显示它实际上并没有做任何事情,因此实际上不会允许重新绘制。如果您将来的所有代码都在func()
AND之内,那么在调用setTimeout()
之后,当前执行线程中没有更多代码可以运行,那么它可能会允许重新绘制。
如果您向我们展示了延迟重新绘制的其余代码,那么我们可以更具体地帮助您。您展示的代码不会延迟重新绘制。