解析dom元素的更有效方法?

时间:2011-07-07 18:21:59

标签: javascript dom

我需要解析一些HTML。

基本上我正在走过给定元素的dom。抓取文本节点和元素节点。

当我遇到文本节点时,我会逐个字符地将它们打印成不同的元素。每个角色都放置在它自己的范围内,具有自己的风格,该风格取自任何附有样式的元素节点。

因此,当找到元素节点时,它的样式将应用于检测到的任何文本节点,直到找到另一个元素节点并且旧样式被替换为新样式。

以下代码有效。如果源元素中有句子或短段落,则会在不到一秒的时间内准确地再现文本。文本越长,花费的时间越长(duh)。

有趣的是,目标元素中已有的文本越多,所需的时间就越长。因此,如果我在相同的源元素上运行此函数10次,并且处理相同的文本正文,则它将比第1次通过第10次运行速度慢,可能是因为在元素中渲染文本更难那已经有了内容。

无论如何,我真的需要找到一种让这个东西跑得更快的方法。

最后,这是一个可能需要处理的HTML代码段示例:

<span style='blah: blah;'> Some text </span><span>Even more text </span> <p> stuff </p>

生成的HTML将是:

<span style='blah: blah;'>S</span>
<span style='blah: blah;'>o</span>
<span style='blah: blah;'>m</span>
<span style='blah: blah;'>e</span>
<span style='blah: blah;'> </span> 
<span style='blah: blah;'>t</span>
<span style='blah: blah;'>e</span>
<span style='blah: blah;'>x</span>
<span style='blah: blah;'>t</span> 
.......

没什么特别的。

以下是代码:

代码:

ed.rta_to_arr_paste = function(ele, cur_style) {

    var child_arr = ele.childNodes;

    if(!(is_set(cur_style))) {
        cur_style = {};
    }

    for(var i = 0; i < child_arr.length; i++) {
        if(child_arr[i].nodeType == 1) {
            if(cur_style != child_arr[i].style) {
                cur_style = child_arr[i].style;
            }
        } else if(child_arr[i].nodeType == 3) {

            for(var n = 0; n < child_arr[i].nodeValue.length; n++) {

                var span = ed.add_single_char(child_arr[i].nodeValue.charAt(n), cur_style);
            }
        }
        ed.rta_to_arr_paste(child_arr[i], cur_style);
    }

}

编辑:
像这样使用的系统的一个例子是谷歌文档。

当用户将文本粘贴到文档中时,它首先在屏幕上呈现,然后使用与此类似的函数(我假设)进行处理。然后它重新打印文档中的文本。 这一切都发生得非常快(除非文字很长)。

2 个答案:

答案 0 :(得分:5)

您似乎直接将新元素插入到DOM树中,因此我认为您可以通过不那样做来获得最佳改进。

避免逐个插入大量元素。每次插入元素时,浏览器都必须重新计算页面的布局,这需要时间。

相反,将节点添加到不在DOM中的元素,最好使用DocumentFragment,可以通过document.createDocumentFragment创建。

然后你所要做的就是插入这个片段,浏览器只需要重新计算一次。

<强>更新

您还可以尝试使用正则表达式将文本转换为span元素。

var html = value.replace(/(.)/g, "<span>$1</span>")

至少在我的天真测试中(不确定测试用例是否这样好),它比创建span元素并将它们添加到文档片段要好得多:

更新2:我将测试调整为设置生成的元素/字符串作为元素的内容,遗憾的是,这会消除使用{{{ 1}}。但它仍然值得测试:

http://jsperf.com/regex-vs-loop


您还应避免重复访问属性:

replace

答案 1 :(得分:0)

看起来你正在每次调用时在DOM中搜索一个元素。我认为你会把事件附加到DOM元素上,比如onload(或者更好的是使用jquery document.ready)。我也会(作为次要重构)在调用for循环之前首先检查以确保你有孩子(child_arr.length> 0)(这可能是完全无关紧要但最佳实践)