JavaScript:如何在执行JavaScript代码之间设置简单的延迟?

10

我有一个 for 循环在 JavaScript 代码中迭代超过 10,000 次。该循环会创建并添加 < div > 标签到当前页面 DOM 中的一个盒子中。

for(i = 0; i < data.length; i++)
{
    tmpContainer += '<div> '+data[i]+' </div>';
    if(i % 50 == 0) { /* some delay function */ }
}
containerObj.innerHTML = tmpContainer;
我想在每50个
标签之后添加延迟,那么在该位置上的代码应该是什么?
/* some delay function */

因为加载所有10,000个 <div> 标签需要太长时间,我想以每50个 <div>标签的块来更新盒子。

提前致谢。

5个回答

16
在这种情况下有一个方便的技巧:使用 0 毫秒的 setTimeout。这将导致 JavaScript 让出控制权给浏览器(以便它可以执行渲染、响应用户输入等),但没有强制它等待一定时间:
for (i=0;i<data.length;i++) {
    tmpContainer += '<div> '+data[i]+' </div>';
    if (i % 50 == 0 || i == data.length - 1) {
        (function (html) { // Create closure to preserve value of tmpContainer
            setTimeout(function () {
                // Add to document using html, rather than tmpContainer

            }, 0); // 0 milliseconds
        })(tmpContainer);

        tmpContainer = ""; // "flush" the buffer
    }
}

注意: T.J. Crowder在下面正确地指出,上述代码将在每个循环迭代中创建不必要的函数(一个用于设置闭包,另一个作为setTimeout的参数)。这可能不是问题,但如果您希望,可以查看他提供的替代方案,该方案只会创建一次闭包函数。

请注意:尽管上述代码可以提供更愉悦的呈现体验,但在页面上放置10000个标签并不可取。之后每个其他DOM操作都会变慢,因为有更多的元素需要遍历,并且任何布局更改都需要进行更昂贵的回流计算。


1
那样做可以,但有两个注释:1.每次达到50个div时都会不必要地创建一个新函数。这是199个不必要的函数。可能还好,但仍然是可以避免的。2.使用字符串数组构建HTML,然后在完成时使用a.join("")创建一个大字符串比使用字符串连接构建HTML更有效率。 - T.J. Crowder
@T.J. 你说的两点都是对的,但出于简单起见我没有考虑:1. 函数创建很少会成为性能问题,特别是当瓶颈在于 DOM 时;2. 字符串拼接只在 IE 上存在问题,在其他浏览器中通常更快,但即使在 IE 中,由于我将 tmpContainer 重置为空字符串,所以字符串永远不会变得很大 ;) - David Tang
@Box9:刚看到了:**document.write**?!?这根本行不通。使用appendChild等方法是可以的。 - T.J. Crowder
@Box9:有趣的"工作"解释。;-) 我会将其删除,因为完全是误导性的,只留下注释 "在这里使用html创建元素"。顺便说一下,我之前错了,它有大约398个完全不必要的函数(你正在重新创建创建闭包的东西,甚至没有比其他需要更少)。此外,除非 data.length % 50 == 0,否则这将无法输出最后的1-49或者至少需要重复代码来完成。而应该使用这个代码:http://pastie.org/1533736 这一切都是为了给出一个好答案,而不是给你添麻烦。 - T.J. Crowder
@Box9:很高兴能与一个不那么敏感的人进行互动。 :-) 最好的祝福, - T.J. Crowder
显示剩余4条评论

3
你可以使用 window.setTimeout 函数来延迟执行某些代码:
if(i % 50 == 0) {
    window.setTimeout(function() {
        // this will execute 1 second later
    }, 1000);
}

但是您的 JavaScript 代码将继续执行,不会停止。


1
我会将创建 div 的代码拆分到一个函数中,并使用 setTimeout 定期调用该函数,方法如下:
function createThousands(data) {
    var index;

    index = 0;
    doAChunk();

    function doAChunk() {
        var counter;

        for (counter = 50; counter > 0; --counter) {
            // Are we done?
            if (index >= data.length) {
                // Yup
                return;
            }

            // ...create a div...

            // Move to the next
            ++index;
        }

        // Schedule the next pass
        setTimeout(doAChunk, 0); // 0 = defer to the browser but come back ASAP
    }
}

这里使用了单个闭包doAChunk来完成工作。该闭包在完成其工作后可以进行垃圾回收。(更多信息: 闭包并不复杂)

实时演示


@fehergeri:我的问题?哼? - T.J. Crowder
@fehergeri:哦,我明白了,你指的是他的问题。我正在处理不进行中间更新的问题;重新排版是完全不同的事情。 - T.J. Crowder

1

由于回流,它需要很长时间。您应该创建一个文档片段,然后添加 brats。

DOM 环境下何时发生回流?

JavaScript 性能 - Dom 回流 - Google 文章

睡觉不会解决您的问题

另一方面,您可以创建一个包含 innerHTML 的字符串,然后将其添加到 innerHTML 中。字符串的性能确实不需要太高,但是当您执行 .innerhtml 命令时,它会启动一个进程,解析您的字符串并创建元素并将它们附加。您无法中断或添加延迟。

innerHTML 进程无法休眠或中断。

您需要逐个生成元素,并在添加 50 个元素后创建 settimeout 延迟。

var frag = document.createDocumentFragment();

function addelements() {

   var e;
   for(i=0;i<50;++i) {
       e = document.createElement('div');
       frag.appendChild(e);
   }
   dest.appendChild(frag);
   window.setTimeout(addelements,1000);

}

-1

这里是在JavaScript中放置延迟而不挂起浏览器的真正技巧。您需要使用带有同步方法的ajax函数,该函数将调用一个php页面,在该php页面中,您可以使用sleep() php函数!http://www.hklabs.org/articles/put-delay-in-javascript


2
请注意,仅链接答案是不被鼓励的,SO答案应该是寻找解决方案的终点(而不是另一个参考站点,随着时间的推移往往会变得陈旧)。请考虑在此处添加独立的摘要,将链接作为参考。 - kleopatra

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