0

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

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

但是,由于我们使用下面的函数循环遍历多个节点,因此我添加了一个setTimeout函数,以在每 50 个循环后超时该函数。

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,当过程很长时屏幕也会冻结。

我该如何解决它们?我的意思是我使用了 setTimeout 以便该页面不会变得无响应。

PS:您可以在 Stackoverflow 本身上测试脚本,因为它包含一个 id 为 mainbar 的元素。我同意获取标记名不会花费这么长时间,但我也在计算其他一些东西,例如每个元素的过滤 getComputedStyle,这肯定需要相当长的时间。我把这个问题作为概念证明来了解如何使用 setTimeout 来阻止脚本响应

4

2 回答 2

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);
});
于 2013-10-04T14:52:26.827 回答
2

这里有几个问题:

  1. 你仍然期望在你调用getParentNode之后init,你会在下一行得到你的结果。你不会的。它还没有建成。

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

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

  4. getElementsByTagName由start at返回的列表1,而不是0

如果这需要异步,则需要重构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);
}
于 2013-10-04T14:03:16.103 回答