【问题标题】:Update webpage to show progress while javascript is running in in a loop更新网页以在 javascript 循环运行时显示进度
【发布时间】:2015-11-24 18:49:30
【问题描述】:

我编写了需要 20-30 秒来处理的 javascript,我想通过更新网页上的进度条来显示进度。

我使用 setTimeout 来尝试重新绘制网页。

这就是我的代码的样子:

function lengthyFun(...){
   for(...){
      var progress = ...
      document.getElementById('progress-bar').setAttribute('style',"width:{0}%".format(Math.ceil(progress)));

      var x = ...

      // Processing
      setTimeout(function(x) { return function() { ...  }; }(x), 0);
   }
}

它不起作用,我知道它为什么不起作用,但我不知道如何重构我的代码以使其起作用。

【问题讨论】:

  • 您是否真的在他的 CLIENT 上处理某些东西?这需要 30 秒?
  • "编写了需要 20-30 秒处理的 javascript" 可以在问题中包含 htmljs 吗? , 创建 stacksn-ps , jsfiddle jsfiddle.net 来演示?见stackoverflow.com/questions/27690326/…
  • @ppumkin,是的,我是初学者,只是在尝试使用 javascript。该网页未托管,因此没有服务器。
  • 这可能是问题所在。 JavaScript 永远不应该运行那么久!如果你在做一个 AJAX,你会显示一个加载的 GIF 或者一个简单的进度条,就像这样。为了使进度条非常准确,您需要将进程卸载到服务器,实现包含进度百分比的异步响应。使用 jQuery 也会帮助你分配。
  • @ppumkin 为什么不呢? Javascript 越来越多地用于功能强大的(网络或非网络)应用程序。例如,使用客户端执行一些较长的进程可以避免服务器过载并最大限度地减少网络过载。

标签: javascript html settimeout


【解决方案1】:

我知道有几种方法可以通过 Javascript 触发连续的 HTML 重绘:

  • 增量超时时间
  • 递归方法调用

第一种也是最简单的方法是在循环中对超时间隔使用乘数(例如迭代器)。如果操作独立于外部变量并且只需要运行有限且相对较少的次数,则此方法应该足够了。需要/可能发生的操作越多,对资源的压力就越大——仅用于计算间隔。当处理时间超过超时间隔时,另一个缺点会生效,从而导致观察到的重绘间隔受到连锁反应。这样做的结果可能是网页完全冻结,直到所有操作都完成。

例子

for (var i=0, limit=n; i<limit; i++) {
    setTimeout((function(params) {
        return  function() {
            some_func(params);
        }
    })(param_values), i*1000);
}

第二种方法稍微复杂一些,但保证每次操作之间的重绘,不管超时间隔。在这里,超时只影响重绘之间的时间,并且抵抗连续操作变量的影响。但是,当前操作的处理时间仍然是观察间隔的一个因素,并且如果该操作是计算密集型的,那么在重绘之间仍然会冻结网页。

例子

var limit = n;
var i = 0;
recursive_timeout();
function recursive_timeout() {
    setTimeout((function(params) {
        return function() {
            some_func(params);
            i++;
            if (i<limit) {
                recursive_timeout();
            }
        }
    })(param_values, i, limit), 1000);
}

精炼示例(基于 guest271314 的回答)

var still_true = true;
recursive_timeout();
function recursive_timeout() {
    some_func(params);
    if (still_true) {
        setTimeout(function() {recursive_timeout();}, 1000);
    }
}

虽然增量方法适用于简单任务,但递归将可靠地执行重绘。如果每个操作的处理时间较长是一个问题,那么除了使用递归之外,还值得深入研究异步任务以避免使网页暂时无法使用。

无论如何,希望这会有所帮助!

哈!刚刚意识到 guest271314 提出了一个更优雅的递归方法示例......哦,好吧,更多信息不会有坏处。

【讨论】:

    【解决方案2】:

    您可能知道,这里的问题是您的主进程(需要大量时间的进程)阻塞了任何渲染。那是因为 JavaScript(大部分)是单线程的。

    在我看来,您有两种解决方案可以做到这一点。 第一个是将您的主要流程分成不同的部分,并在每个部分之间进行渲染。 IE。你可以有类似的东西(使用 Promises):

    var processParts = [/* array of func returning promises */];
    
    function start(){
        // call the first process parts
        var firstPartPromise = (processParts.shift())();
        // chain it with all the other process parts interspersed by updateDisplay
        return processParts.reduce(function(prev, current){
            return val.then(current).then(updateDisplay);
        }, firstPartPromise);
    }
    

    你可能需要一个 polyfill 来实现 Promise (one here)。如果你使用 jQuery,他们有一个(糟糕的非标准)实现。

    第二种解决方案是使用webworkers,它允许您在 JavaScript 中创建线程。它适用于所有现代浏览器。 在您的情况下,这可能是最好的解决方案。 我从未使用过它们,但您应该能够执行以下操作:

    var process = new Worker("process.js");
    
    worker.onmessage(function(event){
        updateProgress(event.data.progress)
    });
    

    还有process.js:

    postMessage({progress: 0.1});
    // stuff
    postMessage({progress: 0.4});
    // stuff
    postMessage({progress: 0.7});
    //etc
    

    【讨论】:

      【解决方案3】:

      尝试将progress元素属性min设置为0max设置为20000value设置为0;创建函数,如果value小于max,则将value增加1000;利用setTimeout 将持续时间设置为1000 递归调用函数,直到value 达到max

      var p = document.querySelector("progress");
      
      function redraw() {
         if (p.value < p.max) {
           p.value += 1000;
           setTimeout("redraw()", 1000)
         }
      }
      
      redraw()
      &lt;progress max="20000" min="0" value="0"&gt;&lt;/progress&gt;

      【讨论】:

        猜你喜欢
        • 2011-10-14
        • 1970-01-01
        • 2011-06-07
        • 1970-01-01
        • 2015-05-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多