当javascript在循环中运行时,更新网页以显示进度
Update webpage to show progress while javascript is running in in a loop
我已经写了javascript,需要20-30秒来处理,我想通过更新我的网页上的进度条来显示进度。
我使用了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);
}
}
它不工作,我知道为什么它不工作,但我不知道如何重构我的代码使它工作
您可能知道,这里的问题是您的主进程(花费大量时间的进程)阻塞了任何呈现。这是因为JavaScript(大部分)是单线程的。
在我看来,你有两种解决办法。第一种方法是将你的主要过程分成不同的部分,并在每个部分之间进行渲染。也就是说,你可以有这样的东西(使用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。如果你使用jQuery,他们有一个(糟糕的非标准)实现。
第二个解决方案是使用webworkers,它允许你在JavaScript中创建线程。它适用于所有现代浏览器。对于您的情况,这可能是最好的解决方案。我从未使用过它们,但你应该能够做这样的事情:
var process = new Worker("process.js");
worker.onmessage(function(event){
updateProgress(event.data.progress)
});
和in process.js
:
postMessage({progress: 0.1});
// stuff
postMessage({progress: 0.4});
// stuff
postMessage({progress: 0.7});
//etc
尝试设置progress
元素属性min
为0
, max
为20000
, value
为0
;如果value
小于max
,则value
增加1000
;使用持续时间设置为1000
的setTimeout
递归调用函数,直到value
到达max
var p = document.querySelector("progress");
function redraw() {
if (p.value < p.max) {
p.value += 1000;
setTimeout("redraw()", 1000)
}
}
redraw()
<progress max="20000" min="0" value="0"></progress>
我知道有几种方法可以通过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提出了一个更优雅的递归方法的例子…好吧,多给点信息也无妨。
- 在网页上显示当前股票报价
- HTML 5 和 3.js 代码不会在网页上显示任何内容
- 使用服务器上的HTML/js在网页上显示图像
- 如何删除在PHP中打印网页时显示的URL
- 如何使用JavaScript函数在网页中显示PHP变量
- 更改当前网页上显示的部分(即不是全部)文本
- javascript从选中的复选框中检索输入值,并在同一网页中显示多个html文件
- 如何让网页显示一次,并且不再向用户显示
- 有效的网页显示在WebKit浏览器和IE中,但不显示在Firefox中
- 使用延迟加载会使我的网页显示得更快吗?
- 如何将网页显示为警报
- 网页显示使用Angular1.4的表达式中的大括号
- 如何保持网页显示期间JavaScript警报在Chrome &FireFox的一个VB ASP.. NET web应用程
- JS成功添加了一个标签,但网页显示失败
- 如何让一个网页显示在另一个网页
- 将外部网页显示为网页
- 使网页显示为完全加载,或jQuery到MooTools的翻译
- 如何从覆盖得到URL,如果网页显示在覆盖
- 外部JS文件导致我的网页显示为空白
- 为什么不是't我的网页显示时间(javaScript)