2010-04-26 16 views
32

क्या डोम में तत्वों की हैश-टेबल है जिनकी चाबियाँ तत्व हैं Iids?
मैं जानना चाहता हूं कि document.getElementById हैश तालिका देखता है या पूरे पेड़ को पार करता है।
क्या यह व्यवहार ब्राउज़र भर में अलग है?जावास्क्रिप्ट getElementById लुकअप - हैश मानचित्र या रिकर्सिव पेड़ ट्रैवर्सल?

+2

+1, अच्छा सवाल। एक बहुत अच्छे सवाल के लिए –

+2

+1। – Kangkan

+2

मुझे पूरा यकीन नहीं है कि यह एक अच्छा सवाल है। एक अच्छा सवाल हो सकता है "किसी दिए गए आईडी के साथ तत्व ढूंढने का सबसे अच्छा तरीका क्या है", और 'getElementById' संभवतः सबसे अच्छा जवाब है। इसे कैसे कार्यान्वित किया जाता है? वह एक काले बॉक्स में peeping है। एक निश्चित उत्तर के लिए शायद बहुत सारे ब्राउज़र हैं। – Kobi

उत्तर

10

कार्यान्वयन जो भी उन्हें पसंद है, करने के लिए स्वतंत्र हैं, लेकिन id को एक अद्वितीय मूल्य के रूप में परिभाषित किया गया है, यह एक हैश मानचित्र या ट्रैवर्सल के बजाय समान लुकअप तंत्र का उपयोग करने के लिए समझदार प्रतीत होता है। बाहर से समझदार प्रतीत होता है, हालांकि, जब आप कई जटिल (कभी-कभी विरोधाभासी) अनिवार्यताओं के साथ एक जटिल वेब ब्राउज़र बनाने की नलसाजी में नहीं आते हैं।

मैंने एक आसान किया लेकिन बहुत सरल परीक्षण (उत्तर के अंत में पृष्ठ देखें)। यह बहुत सरल नहीं है क्योंकि हम नहीं जानते कि ब्राउज़र पिछले परिणामों को कैश नहीं करते हैं।

क्रोम 4.1.249.1059 रिपोर्ट:

ID: 0.0082ms per lookup 
Tag: 0.0249ms per lookup 

तो, नाटकीय रूप से तेजी से टैग नाम से आईडी के आधार पर।

IE7 रिपोर्ट:

ID: 2.4438ms per lookup 
Tag: 0.0437ms per lookup 
आईडी से

तो नाटकीय रूप से तेजी से टैग नाम से (लेकिन याद IE7 एक broken concept of getElementById है, इस IE8 में तय हो गई है)।

IE8 (एक अलग मशीन पर, निरपेक्षता की तुलना नहीं करते, हम ब्राउज़र का परीक्षण भीतर डिफ पर देख रहे हैं) रिपोर्ट:

ID: 1.1335ms per lookup 
Tag: 0.0287ms per lookup 

तो के बारे में IE7 के रूप में ही।

फ़ायरफ़ॉक्स 3.6।3 रिपोर्ट:

ID: 0.0042ms per lookup 
Tag: 0.006ms per lookup 

तो यह है कि ज्यादा परवाह नहीं करता है (कई बार अनुरोध पर; फिर, यह कैशिंग जा सकता है)।

ओपेरा 10.5.1 रिपोर्ट:

ID: 0.006ms per lookup 
Tag: 1.467ms per lookup 
नाटकीय रूप से तेजी से

टैग नाम से आईडी के आधार पर।

उन परिणामों का बनाएं जो आप करेंगे। वास्तव में तंत्र का अनुमान लगाने के लिए एक और जटिल परीक्षण मामले की आवश्यकता होगी। बेशक, कम से कम दो मामलों में (फ़ायरफ़ॉक्स और क्रोम), हम स्रोत पर जा सकते हैं। points usWebKit और Firefox कार्यान्वयन के लिए कृपया (और इसे देखकर, कैशिंग के बारे में मेरा संदेह on the money हो सकता है)।

टेस्ट पेज:

<!DOCTYPE HTML> 
<html> 
<head> 
<meta http-equiv="Content-type" content="text/html;charset=UTF-8"> 
<title>Test Page</title> 
<style type='text/css'> 
body { 
    font-family: sans-serif; 
} 
#log p { 
    margin:  0; 
    padding: 0; 
} 
</style> 
<script type='text/javascript'> 
window.onload = pageInit; 
function pageInit() { 
    document.getElementById('btnGo').onclick = btnGoClick; 
} 
function btnGoClick() { 

    log("Testing..."); 
    setTimeout(run, 0); 
} 

function run() { 
    var count, time; 

    try { 
     // Warm up 
     testid(10); 
     testtag(10); 

     // Test 
     count = 10000 
     time = testid(count); 
     log("ID: " + (time/count) + "ms per lookup"); 
     time = testtag(count); 
     log("Tag: " + (time/count) + "ms per lookup"); 
    } 
    catch (e) { 
     log("Error: " + (e.message ? e.message : String(e))); 
    } 
} 

function testid(count) { 
    var start; 

    start = new Date().getTime(); 
    while (count-- > 0) { 
     if (!document.getElementById('fred')) { 
      throw "ID 'fred' not found"; 
     } 
    } 
    return new Date().getTime() - start; 
} 

function testtag(count) { 
    var start; 

    start = new Date().getTime(); 

    while (count-- > 0) { 
     if (document.getElementsByTagName('em').length == 0) { 
      throw "Tag 'em' not found"; 
     } 
    } 
    return new Date().getTime() - start; 
} 

function log(msg) { 
    var log = document.getElementById('log'); 
    log.innerHTML += "<p>" + msg + "<\/p>"; 
} 
</script> 
</head> 
<body><div> 
<input type='button' id='btnGo' value='Go'> 
<div id='log'></div> 
<hr> 
<div>test test<span>test<span>test<span>test<span>test</span></span></span></span></div> 
<div>test test<span>test<span>test<span>test<span>test</span></span></span></span></div> 
<div>test test<span>test<span>test<span>test<span>test</span></span></span></span></div> 
<div>test test<span>test<span>test<span>test<span>test</span></span></span></span></div> 
<!-- repeat the above a couple of thousand times; I had about 2,200 --> 
<div>test test<span>test<span>test<span>test<span>test</span></span></span></span></div> 
<div>test test<span>test<span>test<span>test<em id='fred'>test</em></span></span></span></div> 
</div></body> 
</html> 
+1

यहां रुचि रखने वाले किसी भी व्यक्ति के लिए लाइव उदाहरण है http://jsbin.com/esemi3/ – R0MANARMY

+0

@ROMANARMY: इसे * बहुत * अधिक सामग्री की आवश्यकता है (HTML में इनलाइन टिप्पणी देखें)। –

+0

@ टीजे।- अच्छा परीक्षण, मैंने जेएसबीएन पर सामग्री जोड़ने की कोशिश की, लेकिन ऐसा लगता है कि उनके पास आकार सीमा है, मैंने इसे अपलोड किया है [यहां] (http://dl.dropbox.com/u/35146/js/tests/getElementById .html)। – CMS

0

परीक्षण करना मुश्किल नहीं होना चाहिए।

यदि यह पेड़-आधारित है तो बहुत गहरे पेड़ (जावास्क्रिप्ट के माध्यम से) बनाना एक अच्छा परीक्षण केस होना चाहिए।

+3

कृपया प्रश्न का उत्तर दें और प्रतिनिधि पाने के लिए पोस्ट न करें। –

+2

हां, कृपया कम से कम 3 प्रमुख ब्राउज़रों पर, वह परीक्षण करें। – Kobi

+0

@ श्रीनिवास: क्या आपने मेरा प्रतिनिधि देखा है? मुझे परवाह नहीं है। –

2

विशिष्ट कार्यान्वयन HTML spec में परिभाषित नहीं किया गया है, इसलिए यह ब्राउज़र को ब्राउज़र में आसानी से बदल सकता है। उदाहरण के लिए IE documentation राज्य

आईडी या NAME विशेषता के निर्दिष्ट मान के साथ पहली वस्तु का संदर्भ देता है।

इसलिए मुझे यह कहने का लुत्फ उठाना होगा कि यह एक खोज करता है (या यह हैश टकराव के मामलों में तत्वों को फेंकता है)।

EDIT यह भी ध्यान रखें कि अन्य डेटा संरचनाएं (पेड़ों की तरह) हैं जो निरंतर और रैखिक के बीच कहीं भी पहुंचने की अनुमति देती हैं।

+0

याद रखें कि आईई के कार्यान्वयन - आपके द्वारा उद्धृत बिट - डब्ल्यू 3 सी द्वारा निर्दिष्ट व्यवहार के साथ पूरी तरह से बाधाओं में टूटा हुआ है। उन्होंने भाग्य से IE8 में इसे ठीक किया। –

+0

अच्छा बिंदु। निष्पक्ष डब्ल्यू 3 सी कहने के लिए ** ... व्यवहार को परिभाषित नहीं किया गया है यदि एक से अधिक तत्वों में यह आईडी है। ** यदि सही व्यवहार परिभाषित नहीं किया गया है तो तकनीकी रूप से IE गलत नहीं हो सकता है। – R0MANARMY

+2

@ROMANARMY: गलत बिट 'id' के साथ' name' intermixing है। यदि आपके दस्तावेज़ों में डुप्लिकेट आईडी हैं, जैसा कि आप कहते हैं, जो भी ब्राउज़र करना चाहता है (उन सभी को अनदेखा करने सहित) बिल्कुल ठीक है। –

23

मैं फ़ायरफ़ॉक्स और वेबकिट DOM क्रियान्वयन के बारे में पता है, उन दोनों को एक hashtable का उपयोग तत्वों देखने के लिए, उनमें से स्रोत में खुदाई आप आंतरिक कार्यान्वयन करने के लिए एक तरह दे सकते हैं : यदि id अद्वितीय है

वेबकिट कार्यान्वयन, Document.cpp, hashtable का उपयोग करता है, अन्यथा यह दस्तावेज़ को पार करता पहला मैच पाने के लिए:

Element* Document::getElementById(const AtomicString& elementId) const 
{ 
    if (elementId.isEmpty()) 
     return 0; 

    m_elementsById.checkConsistency(); 

    Element* element = m_elementsById.get(elementId.impl());//<-- hastable lookup 
    if (element) 
     return element; 

    if (m_duplicateIds.contains(elementId.impl())) { 
     // We know there's at least one node with this id, 
     // but we don't know what the first one is. 
     for (Node *n = traverseNextNode(); n != 0; n = n->traverseNextNode()) { 
      if (n->isElementNode()) { 
       element = static_cast<Element*>(n); 
       if (element->hasID() && 
       element->getAttribute(element->idAttributeName()) == elementId) { 
        m_duplicateIds.remove(elementId.impl()); 
        m_elementsById.set(elementId.impl(), element); 
        return element; 
       } 
      } 
     } 
     ASSERT_NOT_REACHED(); 
    } 
    return 0; 
} 

फ़ायरफ़ॉक्स कार्यान्वयन, nsDocument.cpp

+2

+1 दिलचस्प। इसलिए, एक ही आईडी आईडी का उपयोग न केवल आपके दस्तावेज़ को अमान्य बनाता है, बल्कि यह प्रदर्शन को और भी खराब बनाता है। – bobince

+0

@ सीएमएस हैशटेबल का उपयोग कैशिंग के लिए किया जा सकता है। हम केवल तभी जानेंगे जब हम बड़े डोम पर परीक्षण चलाते हैं। – sash

+0

कमाल का जवाब, धन्यवाद – foreyez

संबंधित मुद्दे