非递归遍历 DOM 结构

上次在Google+ 上说 实现了非递归遍历 DOM 结构, 有朋友想让分享,我当然很高兴,但是很遗憾这本身没有什么值得分享的,大致如下, 给大家随便看一下:

常见的递归方式遍历方式,下面是 Douglas Crockford 写的递归实现:

1function walkTheDOM (node, func) {
2    func(node);
3    node = node.firstChild;
4    while (node) {
5        walkTheDOM(node, func);
6        node = node.nextSibling;
7    }
8}

然后有人自称写出了更快的遍历 DOM 方式。

1var elems = document.getElementsByTagName("*");
2for(var i=0,l=elems.length; i<l; i++){
3    handler(elems[i]);
4}

最初找到有详细对照的文章地址没有找到,这个是 类似的一篇, 而且也是非递归式的。

确实是很快的,但只是快还是不够的,这个实现有很多弊端:

  1. 注释等元素未必会被遍历。
  2. 树形数据结构被整理成了平板结构,无法实现遍历过程的 in/out 处理。

然后今天的主角隆重登场:

1function walk(node, enter, leave){
2    var tmp, n=node;
3    label:
4    do{
5        enter(n);
6        if(tmp = firstNode(node)){ // firstChild(HTMLElement)
7            n = tmp;
8        }else if(tmp = nextNode(n)){ // nextSibling(HTMLElement)
9            n = tmp;
10        }else if(n.parentNode){
11            do{
12                n = n.parentNode;
13                leave(n);
14                if(n == node){break label;}
15                if(tmp = nextNode(n)){
16                    n = tmp;
17                    continue label;
18                }
19            }while(node);
20        }else{
21            break;
22        }
23    }while(n && n!=node);
24}

上面只是一个精简版,实际过程中还需要考虑节点类型的问题,一般会过滤 1:HTMLElement, 8:Comment, 9:Document Type, 10:DocType 之外的节点。

其实也不过如此嘛,飘过~~

See Also


Tags: JavaScript, 算法

Published on 2011-07-10

ON THIS PAGE