-2

我知道也许这是不可能的。我已经搜索了网络,但没有成功

我有一个while循环,我想做两件事:

  1. 使用格式化信息更新文本区域
  2. 更新 div 的宽度(进度条)。

第一个功能有 4-5 个附加子功能。

基本上我有一个 6 个元素的数值数组。我有一个自定义格式函数来为我的数字创建格式化的字符串元素。等等

if (reg_index/reg_total > last_refresh) {    
    window.setTimeout ( 
        function() {
            document.getElementById("progress_line").style.width = "" + 100 * last_refresh + "px";
            document.getElementById("progress_value").innerHTML = my_format( 100*last_refreh, "###" ) + "%"; 
        },

        5
    );

    last_refresh+=0.01; 
}

好的,我无法定义正确的超时间隔来获得我想要的。

任何人都可以指出一个有用的链接吗?

谢谢。

4

1 回答 1

2

您在这里遇到的问题是您的所有函数都将使用last_refresh. 当你定义一个函数时,它对范围内的变量有一个持久的引用,而不是创建它时它们的值的副本。更多:闭包并不复杂

你可以这样做:

function update() {
    if (reg_index/reg_total>last_refresh) 
        document.getElementById("progress_line").style.width =" "+100*last_refresh+"px";
        document.getElementById("progress_value").innerHTML=my_format(100*last_refreh,"###")+"%"; 
        last_refresh+=0.01; 
        setTimeout(update, 0); // Or 5 or whatever
    }
}
update();

它使用一个功能来完成一些工作,然后安排自己立即完成更多工作。它关闭了reg_indexreg_totallast_refresh变量。

如果你知道它至少需要运行一次,你可以让它更高效一些:

function update() {
    document.getElementById("progress_line").style.width =" "+100*last_refresh+"px";
    document.getElementById("progress_value").innerHTML=my_format(100*last_refreh,"###")+"%"; 
    last_refresh+=0.01; 
    if (reg_index/reg_total>last_refresh) 
        setTimeout(update, 0); // Or 5 or whatever
    }
}
update();

为了帮助理解循环的概念setTimeout,比较这个标准循环(浏览器直到最后才会更新):Live Copy | 直播源

var a = ["zero", "one", "two", "three", "four", "five"];
var index;

for (index = 0; index < a.length; ++index) {
    display("Entry " + index + " is " + a[index]);
}

...使用这个等效的 using setTimeout,它在每次迭代时都会让浏览器更新,因此它可以更新(即使间隔是0,它的运行速度也会慢得多——我在200这里使用过,所以你可以看到它运行):Live Copy | 直播源

var a = ["zero", "one", "two", "three", "four", "five"];
var index;

index = 0;
update();
function update() {
    display("Entry " + index + " is " + a[index]);
    ++index;
    if (index < a.length) {
        setTimeout(update, 200);
    }
}

下面你说:

不幸的是,我无法在我的示例中应用......我有一个在本地数据库上读取 2000 次的主循环......我已经使用超时完成了它,但现在我的代码花费了很多时间

我通常通过将事情分解成块来处理这个问题(或者参见下面的另一种选择),例如:Live Copy | 直播源

var index;
var total = 10000; // 10,000 to do in total

index = 0;
update();
function update() {
    var limit = Math.min(index + 100, total); // Do them 100 at at time
    while (index < limit) {
        if (index % 10 == 0) {
            display("Process entry #" + index);
        }
        ++index;
    }
    if (limit < total) {
        setTimeout(update, 200);
    }
}

选择块的大小,这样您就可以足够频繁地更新(yield),但不要更新(yielding)太多以至于浪费太多时间。上面是根据循环的数量来做的,但另一种方法是让自己运行(比如说)一整秒然后屈服。你可以在一秒钟内完成很多工作。

另一种选择是使用网络工作者,至少在支持它们的浏览器上我在 Stack Overflow 上的其他答案有一个讨论和示例。

但是,即使您使用网络工作者,您也可能希望将工作分成块,因为如果您有 2,000 条记录要通过,那么将进度条更新 2,000 次是没有意义的 &mdasdh; 您只需进行人类无法轻易感知的更新。100 次更新就足够了,甚至可能只有 20 条(因此,100 条记录/块)就可以了。

于 2013-07-15T15:24:04.577 回答