[JS/DOM] getElementById

Pagina: 1
Acties:
  • 183 views sinds 30-01-2008
  • Reageer

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Topicstarter
Voor mijn huidige project hebben we een overzicht (table) met ZEER VEEL rijen. Het aantal varieert van 40 tot 1500. Op al deze rijen worden JavaScript operaties toegepast. Momenteel zitten we met het probleem dat er zeer veel document.getElementById()'s worden uitgevoerd. In totaal vele duizenden keren.

Caching lost niks op, want we hebben steeds een ander element nodig.

Maar we lopen steeds door het hele DOM heen, terwijl we maar in een zeer kleine en afgebakende subset zoeken van de DOM, namelijk steeds één TR.

Dus ik dacht: dan doen we gewoon trElementje.getElementById('id');

Maar dat wordt niet ondersteund.

Iemand een idee?

Ik wil dus een element binnen een (root) element op basis van een ID zoeken.

Fat Pizza's pizza, they are big and they are cheezy


Verwijderd

Combineren met getElementsByTagName("TR") zou volgens mij moeten werken.

getElementsByTagName("TR").document.getElementById("id")

  • b19a
  • Registratie: September 2002
  • Niet online
Schrijf dan zelf een kleine functie die over de subelementen van de TR kan itereren. Hoeft helemaal niet moeilijk te zijn (gebruik bv een regex).

  • user109731
  • Registratie: Maart 2004
  • Niet online
Zoiets:

JavaScript:
1
2
3
4
5
6
7
function getDescendantById(parent, id) {
  var c = parent.getElementsByTagName('*');
  for(var i=0; i<c.length; i++) {
    if (c[i].id == id) return c[i];
  }
  return false;
}

Als dit niet snel genoeg is zou je naar childNodes kunnen kijken, maar dan word de functie wel wat langer omdat childNodes enkel de directe 'kinderen' bevat, en je dus ook weer daarin moet zoeken... :)

Als van het element dat je zoekt het type ook al vaststaat zou je bovenstaande functie kunnen versnellen door * te vervangen door de gewenste tagname, desnoods optioneel dmv een extra argument.

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
XPath zou hier ook goed voldoen. Ik weet niet hoe performant dat is, dus daar zou je even mee moeten testen. Een XPath die zou voldoen is dit:

code:
1
descendant::tr[@id='een_waarde']


En dan vanuit de context van je element.

Overigens behoort een ID uniek in je gehele document te zijn, dus mischien dat je de benaming strategie van je rijen wat kunt aanpassen, als dat mogelijk is?

Noushka's Magnificent Dream | Unity


  • Suaver
  • Registratie: Januari 2004
  • Laatst online: 19-11-2025

Suaver

jokecoat

Als alle TR's toch 'n unique ID hebben? Kan je het makkelijk opzoeken hoor.

JavaScript:
1
2
3
4
function search(row) {
  var result = document.getElementById(row);
  // insert wat je met de betreffende row wil doen.
}

You, me, us, together, me, us, you, we, us, you, me... DONE.


Verwijderd

De vraag is ook of je niet references naar DOM elementen kunt opslaan in variabelen. Dat is vele, vele malen sneller dan elke keer DOM methoden gebruiken. Maak veel gebruik van het doorgeven van this of referenties naar andere objecten, en je script zal stukken sneller worden.

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Topicstarter
Dank allen voor de snelle reacties, maar het probleem is vooral dat mijn DOM enorm is (lees: tot megabytes). Bovendien heb ik een element zo goed als nooit meer dan 1x nodig.

Met een ID kan ik de elementen vrij goed ophalen, met tagname minder, omdat ik onderscheid moet maken tussen verschillende soorten INPUT elementen. Er staan namelijk allemaal hiddens tussen die ik negeer en checkboxen waarvoor weer andere dingen geregeld moeten worden dan voor invoervelden.

Als je twijfels hebt bij het design van de pagina, dat heb ik persoonlijk ook, maar het is een eis van de klant dat in dit scherm vanalles gedaan kan worden en dat ook nog eens over veel data.

@Grote Prutser: Ik heb zelf idd zo'n functie gemaakt, juist met childnodes, maar ik hoopte met een standaard DOM methode iets van optimalisatie te kunnen meepikken of iets dergelijks.

Verder bevatten alle event handlers al een this, maar het is vooral de initialisatie waarin alle records doorlopen worden.

Fat Pizza's pizza, they are big and they are cheezy


Verwijderd

Bij hele grote XML documenten is SAX veel efficiënter dan DOM. Het nadeel is dat je niet in 1 keer iets in een heel document kan opzoeken, maar dat je het hele document moet doorlopen op zoek naar wat je nodig hebt. Dat is tegelijkertijd ook het voordeel, het kost veel minder resources om een document te parsen met SAX.

  • Clay
  • Registratie: Oktober 1999
  • Laatst online: 09-02 10:42

Clay

cookie erbij?

Je bent je er bewust van dat een table (en/of tbody) element een .rows nodelist bevat waar alle tr's inzitten? Het snelste lijkt mij namelijk daardoorheen te lopen, en met een regex op de tbody.rows.item(i).getAttribute('id') te checken.

Wat ben je eigenlijk aan het doen? Als we nml wat meer weten over waar je per se een TR voor op wil zoeken is er wellicht een manier te bedenken waarop dat helemaal niet hoeft.

[ Voor 3% gewijzigd door Clay op 01-11-2006 20:15 ]

Instagram | Flickr | "Let my music become battle cries" - Frédéric Chopin


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Topicstarter
Ik ben een overzicht aan het maken waarin voor elke rij verschillende acties te doen zijn. Die acties worden verricht via checkboxen (meerdere rijen tegelijk selecteren), drop down selects waarmee statussen in te stellen zijn (dynamische lijst, afhankelijk van de status van die ene rij in de applicatie, doorgaans een stuk of 5 - 10 opties), en bij sommige selectieopties moet nog extra info ingevoerd worden middels invoervelden die op dezelfde rij staan (zijn er ook weer 6). Daarnaast nog een aantal radiobuttons voor de meest voorkomende zaken uit de drop down select (schijnt goed te zijn voor de handling van de gebruiker).

Al met al toch een heel stel componenten op elke rij. Dit, samen met de grote hoeveelheid rijen, zorgt voor een enorme webpagina die zeer traag wordt.

De rijen ophalen is geen probleem, dat is idd table.tbodies[0].rows, maar eenmaal in die row beland, wil ik mijn getelementbyid binnen die row uitvoeren en niet over het hele DOM, in verband met performance.

Het werkt functioneel nu ook, het is alleen traag. En ik denk dat dat komt omdat ik over het hele DOM zoek, terwijl ik al weet in welke node ik moet zijn en de zoekactie sterk kan inperken.

Overigens kan ik niet het n-de element uit de tr opzoeken, want in de rij staan nog meer tabellen en spans voor de uitlijning en zo.

[ Voor 5% gewijzigd door JKVA op 01-11-2006 20:24 ]

Fat Pizza's pizza, they are big and they are cheezy


  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

Je zou nog iets dergelijks kunnen proberen:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function findElementById(root, id)
{
    var s = [root.firstChild], e , o;

    while ((e = s.pop()))
    {
        do
        {
            if (e.nodeType == 1)
            {
                if (e.getAttribute('id') == id)
                    return e;

                if ((o = e.nextSibling))
                    s.push(o);
                e = e.firstChild;
            }
            else
                e = e.nextSibling;
        }
        while (e);
    }

    return null;
}

Alternatief is iets doen met rowElement.getElementsByTagName('*')

Intentionally left blank


  • Rekcor
  • Registratie: Februari 2005
  • Laatst online: 08-10-2025
Sowieso denk ik dat je moet proberen om het aantal rijen in de tabel (het aantal rijen dat je toont) te verkleinen. We kunnen hier allemaal leuke functies voor je bedenken, het blijven natuurlijk joekels van tabellen. Mijn ervaring is dat JS (vooral in IE) daar zeer traag van wordt, zeker in combinatie met DOM-bewerkingen.

Heb je wel eens aan 'paging' gedacht? D.w.z. toon alleen de eerste vijftig rijen, met boven de tabel javascript gestuurde knoppen om naar de volgende/vorige rij te springen. Je data zou je dan op kunnen slaan in een gewone array en javascript zou je de tabel 'on the fly' kunnen laten genereren. Door de kale data in een array te plaatsen op de pagina (ipv in een kant-en-klare tabel) wordt deze ook veel kleiner.

[ Voor 8% gewijzigd door Rekcor op 02-11-2006 06:35 ]


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Topicstarter
Rekcor schreef op donderdag 02 november 2006 @ 06:34:
Sowieso denk ik dat je moet proberen om het aantal rijen in de tabel (het aantal rijen dat je toont) te verkleinen. We kunnen hier allemaal leuke functies voor je bedenken, het blijven natuurlijk joekels van tabellen. Mijn ervaring is dat JS (vooral in IE) daar zeer traag van wordt, zeker in combinatie met DOM-bewerkingen.

Heb je wel eens aan 'paging' gedacht? D.w.z. toon alleen de eerste vijftig rijen, met boven de tabel javascript gestuurde knoppen om naar de volgende/vorige rij te springen. Je data zou je dan op kunnen slaan in een gewone array en javascript zou je de tabel 'on the fly' kunnen laten genereren. Door de kale data in een array te plaatsen op de pagina (ipv in een kant-en-klare tabel) wordt deze ook veel kleiner.
Ik heb persoonlijk wel 10x voorgesteld om te pagen en filteren en zo, maar daar willen ze niks van weten. Dus ik ben aan het zoeken naar een oplossing die het een beetje werkbaar maakt.

@Crisp: Jij hebt pas in een andere thread al iets dergelijks gepost, iets van getPreviousNode. Die zou veel sneller moeten zijn dan DOM operaties. Geldt dat ook voor deze functie?

Fat Pizza's pizza, they are big and they are cheezy


  • Rekcor
  • Registratie: Februari 2005
  • Laatst online: 08-10-2025
Ik heb persoonlijk wel 10x voorgesteld om te pagen en filteren en zo, maar daar willen ze niks van weten. Dus ik ben aan het zoeken naar een oplossing die het een beetje werkbaar maakt.
Kun je niet zeggen: 'op Tweakers zeggen ze het'? Grote jongens als ze dan niet naar je willen luisteren ;)
@Crisp: Jij hebt pas in een andere thread al iets dergelijks gepost, iets van getPreviousNode. Die zou veel sneller moeten zijn dan DOM operaties. Geldt dat ook voor deze functie?
Jup, Crisp is onze array-expert. Die functies zijn idd r3t3snel! _/-\o_ Is die functie getPreviousNode sowieso geen oplossing voor jouw probleem?

  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

JKVA schreef op donderdag 02 november 2006 @ 12:26:
[...]

@Crisp: Jij hebt pas in een andere thread al iets dergelijks gepost, iets van getPreviousNode. Die zou veel sneller moeten zijn dan DOM operaties. Geldt dat ook voor deze functie?
Het voordeel van deze functie is dat je de scope beperkt tot een opgegeven root-element hetgeen zeker sneller zal zijn dan een getElementById-search in het gehele document.

Het is in feite een hele simpele iteratieve DOM-walker, dezelfde truuk heb ik inderdaad ook toegepast toen in getPreviousNode :)

[ Voor 12% gewijzigd door crisp op 02-11-2006 12:56 ]

Intentionally left blank


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Topicstarter
crisp schreef op donderdag 02 november 2006 @ 12:55:
[...]

Het voordeel van deze functie is dat je de scope beperkt tot een opgegeven root-element hetgeen zeker sneller zal zijn dan een getElementById-search in het gehele document.

Het is in feite een hele simpele iteratieve DOM-walker, dezelfde truuk heb ik inderdaad ook toegepast toen in getPreviousNode :)
Sooow, de tijdsduur is gedaald van 20 minuten naar 10 seconden. :*)

Waarom zijn die DOM methodes zo traag trouwens? Geven die allemaal overhead ofzo? En waar komt die overhead dan vandaan? Anders gebruik ik voortaan altijd die array functies. _/-\o_

Fat Pizza's pizza, they are big and they are cheezy


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
crisp schreef op donderdag 02 november 2006 @ 12:55:
Het voordeel van deze functie is dat je de scope beperkt tot een opgegeven root-element hetgeen zeker sneller zal zijn dan een getElementById-search in het gehele document.
Is het niet zo dat intern gewoon een lijst met ID's wordt bijgehouden en de daarbij horende elementen? In dat geval zou getElementById wel de snelste methode moeten zijn. Ik kan me haast niet voorstellen dat ze daar zelf niet opkomen. Het lijkt me ook dat dit niet in iedere browser hetzelfde is. Misschien interessant om te testen.

Noushka's Magnificent Dream | Unity


  • Rekcor
  • Registratie: Februari 2005
  • Laatst online: 08-10-2025
Michali schreef op donderdag 02 november 2006 @ 14:23:
[...]

Het lijkt me ook dat dit niet in iedere browser hetzelfde is. Misschien interessant om te testen.
Mozilla's DOM-bewerkingen zijn tig keer zo snel als die van IE, weet ik uit ervaring.

[ Voor 27% gewijzigd door Rekcor op 02-11-2006 14:48 ]


  • user109731
  • Registratie: Maart 2004
  • Niet online
Gecko gebruikt zo te zien intern een hashtable voor het opslaan van ids. KHTML (Konqueror/Safari) gebruikt een soort cache, en als het daar niet in voorkomt gebruiken ze de methode van crisp ongeveer (wel in C++ dan). Erg leuk om te zien hoeveel die op elkaar lijken :)

Maar is het niet logisch dat crisp's manier veel sneller is? Hoe je het ook optimaliseert, je hebt gewoon een veel en veel kleinere hoeveelheid elementen over als je de root al weet... :)

[ Voor 4% gewijzigd door user109731 op 02-11-2006 15:08 ]


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
Rekcor schreef op donderdag 02 november 2006 @ 14:46:
[...]


Mozilla's DOM-bewerkingen zijn tig keer zo snel als die van IE, weet ik uit ervaring.
Dat is mijn ervaring ook wel. Ik heb eens geprobeerd om een HTML filter voor een Rich Text editor te schrijven. Werkt goed, alleen niet in IE. De performance van een stukje HTML filteren is daar echt dramatisch. Dan kun je denken aan 2-3 min. in IE tegenover 5 sec. in Firefox. Gaat helemaal nergens over. Ik ga denk ik eens experimenteren met custom functies, misschien pakt dat wel beter uit dan.

Noushka's Magnificent Dream | Unity


  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

In de meeste browsers is een ID-loopup inderdaad enkel het querieen van een interne hashmap. Hoe IE dat geimplementeerd heeft weet ik niet precies, maar met bestanden van enkele honderden KB's is een getElementById bij mij toch nog sneller dan een DOM-walker.
Ik zou DOM-functies overigens ook nog niet afschrijven, want dit is nog vele malen sneller dan mijn DOM-walker (die ik zelf overigens meestal alleen gebruik als ik non-elementnodes zoek):
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
function findElementById(root, id, tagname)
{
    if (!tagname) tagname = '*';
    var s = root.getElementsByTagName(tagname), i = s.length;
    while (i--)
    {
        if (s[i].id == id)
            return s[i];
    }

    return null;
}

Helemaal als je al weet wat voor soort elementen je zoekt :)

[ Voor 4% gewijzigd door crisp op 02-11-2006 15:15 ]

Intentionally left blank


  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Topicstarter
crisp schreef op donderdag 02 november 2006 @ 15:14:
In de meeste browsers is een ID-loopup inderdaad enkel het querieen van een interne hashmap. Hoe IE dat geimplementeerd heeft weet ik niet precies, maar met bestanden van enkele honderden KB's is een getElementById bij mij toch nog sneller dan een DOM-walker.
Ik zou DOM-functies overigens ook nog niet afschrijven, want dit is nog vele malen sneller dan mijn DOM-walker (die ik zelf overigens meestal alleen gebruik als ik non-elementnodes zoek):
JavaScript:
1
...

Helemaal als je al weet wat voor soort elementen je zoekt :)
Dus als ik een INPUT zoek in een TR waar ik al een referentie van heb, kan ik beter die laatste functie gebruiken? Lijkt me logisch, gezien die interne optimalisaties en gecompileerde code in plaats van geinterpreteerde code.

Fat Pizza's pizza, they are big and they are cheezy


  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

JKVA schreef op vrijdag 03 november 2006 @ 10:26:
[...]

Dus als ik een INPUT zoek in een TR waar ik al een referentie van heb, kan ik beter die laatste functie gebruiken? Lijkt me logisch, gezien die interne optimalisaties en gecompileerde code in plaats van geinterpreteerde code.
Jep, inderdaad.

Overigens zijn form-control elementen vaak ook erg snel op te zoeken op hun name-attribuut middels de form.elements collectie :)

Intentionally left blank

Pagina: 1