如何报告JavaScript函数的进度?

如何报告JavaScript函数的进度?,javascript,progress,repaint,Javascript,Progress,Repaint,我有一个相当长的JavaScript函数,它执行许多任务,我想通过在运行时用消息更新SPAN元素的内容来向用户报告进度。我尝试添加document.getElementById('spnProgress')。innerText=。。。函数代码中的语句 但是,当函数执行时,UI不会更新,因此您只能看到写入SPAN的最后一条消息,这不是很有帮助 我目前的解决方案是将任务分解为多个函数,在每个函数的末尾,我设置SPAN消息,然后使用window.setTimeout调用“触发”下一个函数,延迟很短(比

我有一个相当长的JavaScript函数,它执行许多任务,我想通过在运行时用消息更新SPAN元素的内容来向用户报告进度。我尝试添加document.getElementById('spnProgress')。innerText=。。。函数代码中的语句

但是,当函数执行时,UI不会更新,因此您只能看到写入SPAN的最后一条消息,这不是很有帮助

我目前的解决方案是将任务分解为多个函数,在每个函数的末尾,我设置SPAN消息,然后使用window.setTimeout调用“触发”下一个函数,延迟很短(比如10ms)。这将产生控制,并允许浏览器在开始下一步之前使用更新的消息重新绘制范围

然而,我发现这非常混乱,很难遵循代码,我想一定有更好的方法。有人有什么建议吗?是否有任何方法可以在不离开函数上下文的情况下强制跨度重新绘制


谢谢你的做法是正确的(目前,这可能会随着标准的出现和采用而改变[见Andrew Aylett's],但暂时不会)。您必须这样让步才能允许浏览器进行UI更新。我发现,我越是这样想,事情就越干净,但我最初尝试做这件事时确实很“混乱”。希望你在习惯它时也能找到同样的东西。

这就像是问是否可以在不中断过程的情况下中断一个过程。答案是否定的。您必须使用setTimeout()或setInterval()将控制权传递给浏览器的渲染引擎


如果使用setInterval(),则可以使该进程继续运行,并且在执行函数中只需更新一个外部变量,该变量将由setInterval()调用的函数轮询。这样你只需要打一个电话,而不是在一个循环中打电话。

据我所知不是这样。您可以将代码分解为单个函数可以共享变量的方式,因此:

var a = some_local_state();
runTasksWithProgress([
    function() {
        do_some_work(a);
        a = a + 1;
    },
    function() {
        do_some_other_work(a);
        a = a * 2;
    },
    ...
    ]);
runTasksWithProgress有点棘手。您基本上会调用第一个任务,更新状态,然后设置回调以运行后续任务


这种方法可能会减轻一些痛苦。

您需要知道,在某些浏览器中,如果您有一个长时间运行的脚本,您将收到一条脚本超时消息。因此,实际上需要使用计时器来拆分此文件

话虽如此,如果您正在寻找一种真正结构化的方法来实现这一点,那么您可以查看我为拼写检查项目编写的后台任务库。它允许您针对计时器上的数据数组实现map/reduce


如果函数的工作是在循环中执行的,则类似的操作可能会起作用。 它检查经过的时间量,如果经过1/2秒,则更新进度条。(该示例未经测试。因此,您可能需要使用它。)

var启动;
函数长时间运行(lastState){
开始=(新日期);
对于(变量i=lastState;i<1e6/*=1000000次迭代*/;+i){

如果((新日期)-开始如果您已经控制了目标浏览器,则可以使用在后台进行工作

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);