我有一个很长的JavaScript函数并执行许多任务,我想通过使用消息更新SPAN元素的内容来向用户报告进度。我尝试在整个功能代码中添加document.getElementById('spnProgress')。innerText = ...语句。
然而,当函数执行时,UI不会更新,因此您只能看到写入SPAN的最后一条消息,这对消息没有帮助。
我目前的解决方案是将任务分解为多个函数,在每个函数结束时我设置SPAN消息,然后使用window.setTimeout调用“触发”下一个函数,延迟时间非常短(比如说10ms) )。这会产生控制并允许浏览器在开始下一步之前用更新的消息重新绘制SPAN。
然而,我发现这非常混乱,难以遵循代码,我认为必须有更好的方法。有没有人有什么建议?有没有办法强制SPAN重绘而不必离开函数的上下文?
由于
答案 0 :(得分:7)
你正在采取的方式是正确的方式(目前,这可能会随着标准的出现而被改变并被采纳[见Andrew Aylett的answer],但暂时还没有)。你必须得到这样的结果才能允许浏览器进行UI更新。我发现我觉得这样的事情越多,清洁的事情就会越来越清楚,但我最初的几次尝试确实非常“混乱”。希望你找到与你习惯相同的东西。
答案 1 :(得分:3)
如果您已掌控目标浏览器,则可以使用HTML5 worker thread在后台进行工作。
答案 2 :(得分:2)
您需要注意,在某些浏览器中,如果您有一个长时间运行的脚本,您将收到脚本超时消息。因此,实际上希望使用计时器将其拆分。
话虽如此,如果您正在寻找一种真正有条理的方法,那么您可以查看我为拼写检查项目编写的后台任务库。它允许您对计时器上的数据数组实现map / reduce。
答案 3 :(得分:0)
这就像询问是否可以在不中断程序的情况下中断程序。答案是不。您必须使用setTimeout()或setInterval()将控制权传递给浏览器的渲染引擎。
如果使用setInterval(),则可以继续执行该过程,并在执行函数中简单地更新外部变量,该变量将由setInterval()调用的函数进行轮询。这样你只需要进行一次调用而不是在循环中进行调用。
答案 4 :(得分:0)
不是我知道的。您可以通过各个函数共享变量的方式来分解代码,因此:
var a = some_local_state();
runTasksWithProgress([
function() {
do_some_work(a);
a = a + 1;
},
function() {
do_some_other_work(a);
a = a * 2;
},
...
]);
runTasksWithProgress有点棘手。您基本上会调用第一个任务,更新状态,然后设置回调以运行后续任务。
这种方法可能会减轻一些痛苦。
答案 5 :(得分:0)
如果您的函数的工作是在循环中执行的,那么这样的事情可能会有效。 它会检查已经过的时间量,并在1/2秒过后更新进度条。 (这个例子未经测试。所以你可能需要稍微玩一下。)
var start;
function longRunning(lastState){
start = (new Date);
for(var i = lastState; i < 1e6 /*= 1000000 iterations */; ++i){
if((new Date)-start<500){
// do your stuff;
}
else{
// call a function to update the progress bar
updateProgressBar();
// continue the loop...
setTimeout(function(){longRunning(i);},13);
break;
}
}
}
longRunning(0);