如何报告 JavaScript 函数的进度?

7
我有一个相当长的 JavaScript 函数,执行多个任务。我希望能够通过更新 SPAN 元素的内容以报告进度给用户。我尝试在函数代码中添加 document.getElementById('spnProgress').innerText = …… 语句。但是,在函数执行时,UI 将不会更新,因此您只会看到写入 SPAN 的最后一条消息,这并不是很有用。
目前我的解决方案是将任务分成多个函数,并在每个函数结束时设置 SPAN 消息,然后使用 window.setTimeout 调用下一个函数,延迟非常短(比如 10ms)。这样可以获得控制权,并允许浏览器重新绘制、显示更新的消息,然后再开始下一步操作。
但我发现这种方式非常混乱,难以跟踪代码,我认为应该有更好的方法。有没有人有什么建议?是否有任何方法可以在不离开函数上下文的情况下强制 SPAN 进行重绘?
谢谢。
6个回答

7
你目前的做法是正确的(目前而言,随着标准的出现和被采纳[请参见Andrew Aylett的answer],这可能会改变,但还需要一段时间)。你必须像这样让步,以便允许浏览器进行UI更新。我发现我越是像这样思考,事情就越简洁,但我最初几次尝试做到这一点确实非常“杂乱无章”。希望你在逐渐熟悉这个过程中也能发现同样的事情。

3

如果您可以控制目标浏览器,可能可以使用HTML5工作线程在后台执行工作。


2
请注意,在某些浏览器中,如果您运行的脚本时间过长,您将收到一个脚本超时消息。因此,最好使用定时器来拆分脚本。
话虽如此,如果您正在寻找一种真正结构化的方法,则可以查看我为拼写检查项目编写的后台任务库。它允许您在定时器上对数据数组实现map/reduce。 https://github.com/jameswestgate/taskjs

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有点棘手。您基本上会调用第一个任务,更新状态,然后设置回调以运行后续任务。

这种方法可能会缓解一些痛苦。


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

0

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

如果您使用setInterval(),则可以启动该进程,并在执行函数中简单地更新外部变量,该变量将由setInterval()调用的函数轮询。这样,您只需要进行一次调用,而不是在循环中执行它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接