Javascript:如何在执行 javascript 代码之间设置一个简单的延迟?

Posted

技术标签:

【中文标题】Javascript:如何在执行 javascript 代码之间设置一个简单的延迟?【英文标题】:Javascript: How to put a simple delay in between execution of javascript code? 【发布时间】:2011-06-22 05:02:28 【问题描述】:

我有一个 for 循环,它在 javascript 代码中迭代超过 10,000 次。 for 循环创建 标签并将其添加到当前页面 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 个

标签需要花费太多时间。我想以 50 个 标签块的形式更新该框。

提前致谢。

【问题讨论】:

【参考方案1】:

您可以使用window.setTimeout 函数来延迟某些代码的执行:

if(i % 50 == 0) 
    window.setTimeout(function() 
        // this will execute 1 second later
    , 1000);

但您的 javascript 将继续执行。它不会停止。

【讨论】:

【参考方案2】:

在这些情况下有一个方便的技巧:使用 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 的参数)。这不太可能成为问题,但如果您愿意,可以查看 his alternative,它只创建一次闭包函数。

警告:尽管上面的代码会提供更愉快的渲染体验,但不建议在页面上使用 10000 个标签。在此之后,其他所有 DOM 操作都会变慢,因为要遍历的元素更多,而且对布局的任何更改都会进行更昂贵的回流计算。

【讨论】:

可以,但有两个 cmets: 1. 每次达到 50 个 div 时,它都会不必要地创建一个 new 函数。那是 199 个不必要的功能。可能没问题,但仍然可以避免。 2. 将 HTML 构建成一个字符串数组,然后在完成后使用a.join("") 创建一个大字符串,而不是使用字符串连接来构建 HTML。 @T.J.你对这两点都是正确的,但为了简单起见,我没有打扰:1.函数创建很少是性能问题,特别是当你的瓶颈是 DOM 时,2.字符串连接只是 IE 上的问题,并且在其他浏览器中通常更快,但即使对于 IE,由于我将 tmpContainer 重置为空字符串,字符串永远不会变大;) @Box9:刚看到:document.write?!?!那绝对行不通。 appendChild等都可以。 @T.J.好吧,它会工作,但它只会覆盖您拥有的页面,所以它可能不会按预期工作 ;) 我希望很清楚它只是表明使用变量html 而不是tmpContainer @Box9:对“工作”的有趣解释。 ;-) 我会将其删除,因为它完全具有误导性,并附上评论“在此处使用 html 创建元素”。顺便说一句,我之前错了,它是大约 398 个完全不必要的函数(你正在重新创建 创建 闭包的东西,比另一个更不需要)。此外,除非发生data.length % 50 == 0,否则这将无法输出最后的 1-49,或者至少需要重复的代码才能这样做。取而代之的是:pastie.org/1533736 这是全部,只是为了给出一个好的答案,而不是给你带来困难。【参考方案3】:

我会将创建divs 的代码分解为一个函数,然后通过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 来完成工作。一旦其工作完成,该闭包就有资格进行垃圾收集。 (更多:Closures are not complicated

Live example

【讨论】:

@fehergeri:我的问题?嗯? @fehergeri:哦,我明白了,你的意思是他的问题。我正在处理不进行临时更新的问题;回流完全是另一回事。【参考方案4】:

需要很多时间,因为回流。您应该创建一个文档片段,然后添加小子。

When does reflow happen in a DOM environment?

Javascript Performance - Dom Reflow - Google Article

睡觉不能解决你的问题

另一方面,您创建了一个包含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);


【讨论】:

【参考方案5】:

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

【讨论】:

请注意 link-only answers 是不鼓励的,所以答案应该是寻找解决方案的终点(而不是另一个参考中途停留,随着时间的推移往往会变得陈旧)。请考虑在此处添加独立的概要,并保留链接作为参考。

以上是关于Javascript:如何在执行 javascript 代码之间设置一个简单的延迟?的主要内容,如果未能解决你的问题,请参考以下文章

使用JavaScript

Javascript异步编程的4种方法

Javascript异步编程的4种方法

Javascript异步编程的4种方法

JavaScript基础

[译] 我从没理解过 JavaScript 闭包