SetTimeout没有返回正确的值和无响应的脚本

时间:2013-10-04 13:58:45

标签: javascript jquery firefox settimeout

考虑我想将一个元素的所有后代的tagName放入一个数组中。

var node = document.getElementById('mainbar');

然而,由于我们使用下面的函数循环遍历许多节点,因此我在每50个循环后添加了一个 setTimeout 函数来对函数进行超时。

function MyFunction(root){
    "use strict";
     var myarray = [], descendants, descendant, i=1, l;
     descendants = root.getElementsByTagName('*');

     function getParentNode(){
        for(l = descendants.length; i<l ; i++){
          descendant = descendants[i];
          myarray.push({ tagName: descendant.tagName});

         //  After 50 loops, increment i, setTimeout
          if(i % 50 == 0 ) {
            i++;
            setTimeout(getParentNode, 20);
          }

        }
     }

     function init(){
       getParentNode();
       return   JSON.stringify({ nodes:myarray });
     }

      return init();    
   }

然而,有两个问题:

  1. 不会返回完整的数组(myarray)。
  2. 即使我使用了setTimeout,当进程很长时,屏幕会冻结。
  3. 我该如何解决?我的意思是我已经使用了setTimeout,因此页面不会无响应。

    P.S。:你可以在Stackoverflow上测试脚本,因为它包含一个带有id主栏的元素。  我同意获取Tagname不会花这么长时间,但我也在计算其他一些东西,比如每个元素的过滤getComputedStyle,这肯定需要花费很多时间。我把这个问题作为概念的证明,以了解如何使用setTimeout防止脚本响应

2 个答案:

答案 0 :(得分:3)

忽略其他人提到的所有其他问题,只回答如何完成异步功能的问题。您可以在代码中引入回调的想法。而不是在调用之后立即尝试使用结果,而是在结果准备好后传递要调用的函数:

http://jsfiddle.net/4CdJ2/

function MyFunction(root, callback) {

    /* ... */

    function getParentNode() {
        for (l = descendants.length; i < l; i++) {

            /* ... */

            if (i % 50 == 0) {
                i++;
                setTimeout(getParentNode, 20);
                return;
            }
        }

        // made it out of the loop, must be done
        var result = JSON.stringify({
            nodes: myarray
        });

        callback(result);
    }

    getParentNode();
}

var result = MyFunction(document.getElementById("root"), function(result){
    alert("GOT RESULT: " + result);
});

答案 1 :(得分:2)

这里有几个问题:

  1. 您仍然希望在getParentNode中致电init后,您的结果将在下一行。你不会。它还没有建成。

  2. 基本上与一个相同:MyFunction返回init的结果将不起作用,因为init计划异步处理并在完成之前返回。

  3. getParentNode中,您正在为getParentNode列表中的每个节点循环并安排对descendants调用。你不是异步处理它们,而是一次又安排了大量的回调。

  4. getElementsByTagName返回的列表始于1,而不是0

  5. 如果这需要异步,您需要重构getParentNode以便每次调用处理一个元素。

    但即使是一个非常深层嵌套的结构,你也不太可能需要异步执行此操作,即使在大型文档上也不应该花费那么长时间:

    function MyFunction(root) {
        "use strict";
        var myarray,
            descendants,
            i,
            l;
    
        descendants = root.getElementsByTagName('*');
        myarray = [];
        for (i = 0, l = descendants.length; i < l; i++) {
            myarray.push({
                tagName: descendants[i].tagName
            });
        }
    
        return JSON.stringify(myarray);
    }