• 为什么getElementsByTagName()要比querySelectorAll()快很多?


    相信很多人第一反应当然是这样的了,querySelectorAll的参数是一个css selector,这一步还需要处理呢,肯定会比直接getElementsByTagName要慢了。具体jsperf上有相关的对比,确实getElementsByTagName要比querySelectorAll要快很多,这里不放具体链接了,因为这个网站挂了很长一段时间了已经。

    废话不说,直接看原文Why is getElementsByTagName() faster than querySelectorAll()?

    这里大概翻译一下,觉得不妥的地方还望指教。

    首先这两个方法有个非常明显的区别,一个接受一个tag name的参数,另外一个接受一个css selector。这两个方法最大的不同点是,getElementsByTagName返回的是一个动态的NodeList而querySelectorAll返回的是一个静态的NodeList。

    动态的NodeLists

    NodeList和HTMLCollection是两个特别的对象类型,3级DOM中是这样定义HTMLCollection:

      NodeList和NamedNodeMap在DOM中都是动态的,也就是说,改变这些dom结构都会影响到这些NodeList和NamedNodeMap。例如:如果获取一个有子节点的NodeList,然后增加或者删除子节点,这个NodeList也会动态的改变。同样的,在一个tree结构中改变一个node会影响到所有引用这个node的NodeList和NamedNodeMap对象。

    getElementsByTagName方法即返回的就是这样的一个NodeList,看下面代码

    var divs = document.getElementsByTagName("div"),
        i=0;
    
    while(i < divs.length){
        document.body.appendChild(document.createElement("div"));
        i++;
    }
    

    这是一个死循环,因为divs.length在每次循环都会+1。

    也许这样的动态设计是一个缺陷,但是开发者已经习惯了这种动态的NodeList。

    静态的NodeLists

    querySelectorAll返回的是一个静态的NodeList,下面是 Selectors API

      querySelectorAll返回的是一个静态的NodeList。改变一个相关node不会改变这个静态NodeList对象。也就是说这个对象必须在获取的时候就被创建出来。


    所以即使querySelectorAll返回的结果和getElementsByTagName是一样的,但是他们还是有着本质的区别。在动态NodeList里return的是一个指针,而静态的NodeList返回时当前的node所有信息。

    所以下面这个循环就不是一个死循环

    var divs = document.querySelectorAll("div"),
        i=0;
    
    while(i < divs.length){
        document.body.appendChild(document.createElement("div"));
        i++;
    }
    

    因为在这段代码里,divs.length不会动态的改变。

    所以为什么动态的NodeLists更快呢?

    动态的NodeList返回的更快是因为不需要获取这个节点的所有信息,而静态的需要。为了证明这个观点,可以看一下webkit源码DynamicNodeList.cppStaticNodeList.cpp,这两种对象创建的方式不一样。

    getElementsByTagName创建的过程不需要做任何操作,只需要返回一个指针即可(此处可以理解为shadow clone)。而querySelectorAll会循环遍历所有的的结果,然后创建一个新的NodeList(此处可以理解为deep clone)

    结论

    getElementsByTagName比querySelectorAll快的原因是因为动态和静态NodeList的区别。实际在用的过程中取决于你将要做什么,如果你只是查询一个tag name建议用getElementsByTagName,如果查询的是一个css selector建议使用querySelectorAll。

  • 相关阅读:
    作为一个蒟蒻谈一点考试经验(总结)
    Codeforces Round #517 Div. 2/Div. 1
    Codeforces访问提速攻略(小技巧)
    基数排序模板(基数排序,C++模板)
    k短路模板(洛谷P2483 [SDOI2010]魔法猪学院)(k短路,最短路,左偏树,priority_queue)
    洛谷P4907【CYH-01】小奔的国庆练习赛 :$A$换$B$ $problem$(DFS,剪枝)
    BSGS及扩展BSGS总结(BSGS,map)
    FWT模板(洛谷P4717 【模板】快速沃尔什变换)(FWT)
    洛谷CF264D Colorful Stones(子序列匹配,思维)
    洛谷SP22343 NORMA2
  • 原文地址:https://www.cnblogs.com/childsplay/p/5527999.html
Copyright © 2020-2023  润新知