如何报告 JavaScript 函数的进度?

发布于 08-27 14:34 字数 433 浏览 10 评论 0原文

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

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

我当前的解决方案是将任务分解为多个函数,在每个函数结束时设置 SPAN 消息,然后通过 window.setTimeout 调用以非常短的延迟(例如 10 毫秒)“触发”下一个函数。这将产生控制权,并允许浏览器在开始下一步之前使用更新的消息重新绘制 SPAN。

然而我发现这非常混乱并且很难遵循代码,我想一定有更好的方法。有人有什么建议吗?有没有什么方法可以强制 SPAN 重新绘制而不必离开函数的上下文?

谢谢

I have a JavaScript function which is quite long and performs a number of tasks, I would like to report progress to the user by updating the contents of a SPAN element with a message as I go. I tried adding document.getElementById('spnProgress').innerText = ... statements throughout the function code.

However, whilst the function is executing the UI will not update and so you only ever see the last message written to the SPAN which is not very helpful.

My current solution is to break the task up into a number of functions, at the end of each I set the SPAN message and then "trigger" the next one with a window.setTimeout call with a very short delay (say 10ms). This yields control and allows the browser to repaint the SPAN with the updated message before starting the next step.

However I find this very messy and difficult to follow the code, I'm thinking there must be a better way. Does anyone have any suggestions? Is there any way to force the SPAN to repaint without having to leave the context of the function?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

极致的悲2024-09-03 14:34:46

您这样做的方式是正确的方式(目前,随着标准的出现和采用,这可能会改变[参见 Andrew Aylett 的 answer],但暂时还没有)。您必须像这样屈服才能允许浏览器进行 UI 更新。我发现我越这样想,事情就越干净,但我最初的几次尝试确实相当“混乱”。希望您在习惯后发现同样的事情。

The way you're doing it is the right way (at the moment, this may change as standards emerge and are adopted [see Andrew Aylett's answer], but not for a while yet). You have to yield like that to allow the browser to do its UI updates. I've found that the more I think like this, the cleaner things get, but my first few stabs at doing it were indeed quite "messy." Hopefully you find the same thing as you get used to it.

深爱成瘾2024-09-03 14:34:46

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

If you've got control of the target browser, you may be able to use an HTML5 worker thread to do the work in the background.

且行且努力2024-09-03 14:34:46

您需要注意,在某些浏览器中,如果您有长时间运行的脚本,您将收到脚本超时消息。所以实际上最好使用计时器来分割它。

话虽如此,如果您正在寻找一种真正结构化的方法来执行此操作,那么您可以查看我为拼写检查项目编写的后台任务库。它允许您对计时器上的数据数组实施映射/归约。

https://github.com/jameswestgate/taskjs

You need to be aware that in certain browsers you will receive a script timeout message if you have a long running script. So it is actually desirable to split this using a timer.

Having said this, if you are looking for a really structured way of doing this, then you can look at a background task library I wrote for a spell checking project. It allows you to implement map/reduce against arrays of data on a timer.

https://github.com/jameswestgate/taskjs

谷夏2024-09-03 14:34:46

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

如果您使用 setInterval(),您可以让该过程继续进行,并且在执行函数中只需更新一个外部变量,该变量将由 setInterval() 调用的函数进行轮询。这样您只需进行一次调用,而不必循环调用。

That's like asking whether it's possible to interrupt a procedure without interrupting a procedure. The answer is no. You have to use a setTimeout() or setInterval() to pass control to the browser's rendering engine.

If you use setInterval() you can get that process going and in your executing function simply update an external variable, which will be polled by the function called by setInterval(). That way you only have to make one call instead of doing them in a loop.

寄风2024-09-03 14:34:46

据我所知没有。您可以以这样的方式分解代码,使各个函数可以共享变量,因此:

var a = some_local_state();
runTasksWithProgress([
    function() {
        do_some_work(a);
        a = a + 1;
    },
    function() {
        do_some_other_work(a);
        a = a * 2;
    },
    ...
    ]);

runTasksWithProgress 有点棘手。您基本上会调用第一个任务,更新状态,然后设置回调以运行后续任务。

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

Not that I know of. You could break up your code in such a way that the individual functions can share variables, thus:

var a = some_local_state();
runTasksWithProgress([
    function() {
        do_some_work(a);
        a = a + 1;
    },
    function() {
        do_some_other_work(a);
        a = a * 2;
    },
    ...
    ]);

runTasksWithProgress is a bit tricky. You would basically invoke the first task, update the status, then set up a call-back to run subsequent tasks.

This approach might alleviate some of the pain.

清君侧2024-09-03 14:34:46

如果你的函数的工作是在循环中执行的,这样的事情可能会起作用。
它检查已经过去的时间量,如果已经过去 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);

Something like this may work if your function's work is performed in a loop.
It checks the amount of time that has passed and updates the progress bar if 1/2 second has gone by. (The example is untested. So you may need to play with it a bit.)

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文