【问题标题】:Should I cache document.getElementById() in a variable or call it everytime?我应该将 document.getElementById() 缓存在变量中还是每次都调用它?
【发布时间】:2011-01-11 07:16:09
【问题描述】:

我有很多元素被生成和引用(鼠标悬停、点击、位置变化)很多次。

我手头有这些元素的 ID。将document.getElementById(ID) 调用存储在变量中是否明智,还是每次调用document.getElementById() 更快/一样快/更慢?

var app = [];
var app.elements = []; 
//i can store ['id1', 'id2', 'id3']
//OR ['id1' => document.getElementById('id1'), 'id2' => document.getElementById('id2'), 'id3' => document.getElementById('id3')]

【问题讨论】:

  • 两者都不 - 你应该使用 jQuery!
  • 我正在使用 jQuery。为了提高性能:同样的问题:我应该缓存 jQuery 对象 ($('#id1')) 还是应该在每次需要时调用 $('#id1')?

标签: javascript memory caching performance


【解决方案1】:

将元素存储在变量中当然更快,但幅度不大。这因情况而异,应针对每个情况单独调整。

也许最大的因素是易读性,我相信直接访问元素更具可读性。

theMainButton.style.color = "red";
// vs.
document.getElementById("theMainButton").style.color = "red";

【讨论】:

  • 我在这里寻找性能提升。代码存放在函数中,不需要阅读:)
  • 所有代码都需要阅读,除非第一次写得很完美,永远不需要修改或扩展,永远不需要新功能,也永远不需要理解。 :)
  • 如果将其存储在稀疏数组/映射中会更快吗?我之所以问,是因为 getElementById 基本上已经缓存了 id,所以我不确定缓存已经有 id(最快查找)的元素是否有任何好处,可以保存您要在之前查找的项目时间,但是在查找数据的过程中,您本质上是在做与 getElementById 相同的事情...
  • @Dmitry:可能取决于几件事:浏览器,您使用它的频率(JIT 是否温暖),对象存储在哪里。我无法想象这与性能有关。不过,我有兴趣看到一个基准。
【解决方案2】:

您当然应该尽可能重用引用,但您可能需要在每个函数体中获取新的引用。

例子:

var e1 = document.getElementById('id1');
e1.innerHTML = 'test';
e1.className = 'info';

如果您保留参考的时间更长,您可能会发现它们不再起作用。例如,如果您获取页面一部分的 innerHTML 并将其存储回来,则该部分中的所有元素都将被删除并重新创建。如果您引用了该部分中的某个元素,则该元素不再存在。

// This will recreate all elements inside the 'parent' element:
document.getElementById('parent').innerHTML += 'test';

【讨论】:

  • 这是一个很好的观点,我想补充一点,你永远不知道谁或什么会改变你下面的 DOM 节点。我总是倾向于明确获得参考以减少错误并提高可读性。如果您在高性能情况下处理许多节点,您可能希望将它们分配给内存。
  • 大约有 500 个项目,但它们将得到正确管理。我正在使用 jQuery,并且大多数时候该对象将是 $(jqueryfied),因此我可以调用诸如 position() 之类的函数。将 $('#id1') 对象存储在内存中也一样吗?
  • 哦,现在说得通了。我想知道为什么缓存会跨越函数调用。 (当然,我在那里创造了新元素)。
【解决方案3】:

getElementById 返回一个元素节点,它本质上只是一个 JavaScript 对象。您可以将此对象分配给一个变量,这意味着该变量将在您稍后键入该变量时指向该对象。所以,

var id1 = document.getElementById('id1');

id1 现在指的是具有id 的id1 的DOM 元素。如果没有找到具有该 id 的元素,则 document.getElementById 返回 null。

如果元素保留在 DOM 中并且不会被替换,那么将它们存储在数组中是有意义的,这样您就可以根据需要多次引用它们而不会产生任何性能成本。

如果有帮助,您可以创建一个简单的函数来为您完成:

function getElementsByIds( /* id1, id2 ... */ ) {

    var elems = [];

    for (var i = 0, l = arguments.length; i < l; i++) {
        elems[i] = document.getElementById(arguments[i]);
    }

    return elems;

}

app.elements = getElementsByIds('id1', 'id2', 'id3');

【讨论】:

    【解决方案4】:

    这个问题没有唯一的正确答案。这一切都取决于你必须使用什么。如果您使用的页面在 DOM 树中有大量元素,最好缓存引用并重用它们,以加快查找时间。如果您正在处理一个小页面,最好动态查找元素,并最大限度地减少浏览器的内存消耗。

    这还取决于您定位的浏览器。例如,较新版本的 Firefox 第一次对元素进行细化需要一段时间,但它们会在内部缓存引用,所以下次你要查找它时,它几乎是即时的。另一方面,IE 不缓存查找值,但它的查找时间比第一次尝试的 Firefox 快得多。

    许多现代框架会缓存您为您找到的元素。但是,我个人大部分时间还是更喜欢使用 document.getElementById。当我需要缓存查找值时,我所做的是:

     function registerElement(id)
     {
         if (!this["get_" + id])
            this["get_" + id] = function() {
                var element = document.getElementById(id);
                this["get_" + id] = function() {return element;};
                return element;
            }
     }
    

    您可以通过调用 registerElement 并向其传递元素的 ID 来使用它。当您需要检索该值时,您调用您传递的 get_element id 并在第一次运行时查找元素并缓存它,在每次连续调用时它只会返回缓存值。

    【讨论】:

      【解决方案5】:

      我写了一个小的 JS 例程来做一些基准测试,包括三个测试:-

      1. 从元素中获取值到简单变量中,然后重复赋值,
      2. 重复使用getElementById从元素中获取值,并且
      3. 使用 getElementById 将元素放入变量中,然后重复从该变量中获取。

      测试是在一千万次迭代循环中进行的,显然有很多因素会影响结果(连续运行的数字甚至不完全相同,方差约为 10%),但它们提供了一个“合理的指示”。

      测试 1 - 11 毫秒

      测试 2 - 3983 毫秒

      测试 3 - 3594 毫秒

      一毫秒对你来说可能并不长,但对你的计算机来说,它几乎是永恒的。

      function RunSillySpeedTest(){
      var t1,t2,t3,test1,test2,test3
      var d,e,f,Msg;
      
      d=new Date();
      var t=d.getTime();
      
      //Test 1 - Simple variable assignment
      e=document.getElementById('divelement').innerText;
      for(var i=0; i<10000000; i++){
          f=e;
      }
      d=new Date();
      t1=d.getTime();
      test1=t1-t;
      
      //Test 2 - Repeated getElementById
      for(var i=0; i<10000000; i++){
          f=document.getElementById('divelement').innerText;
      }
      d=new Date();
      t2=d.getTime();
      test2=t2-t1;
      
      //Test 3 - Stored getElementById
      e=document.getElementById('divelement');
      for(var i=0; i<10000000; i++){
          f=e.innerText;
      }
      d=new Date();
      t3=d.getTime();
      test3=t3-t2;
      
      Msg='<b>Test 1 took '+test1+'ms.<br>Test 2 took '+test2+'ms.<br>Test 3 took '+test3+'ms.<br></b>';
      return Msg;
      

      }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-20
        • 2010-11-26
        • 2016-06-19
        • 1970-01-01
        相关资源
        最近更新 更多