Permalänk

[jQuery] 1500-varvsloop och find

Halloj, sitter ute på uppdrag och försöker få ner tiderna på ett JavaScript som pratar med både en webservice och en Java-applet och ritar ut positioner på en karta. En lista med resursikoner ska ändras utifrån datan som kommer tillbaka en gång i minuten. Problemet är bara att detta kan ta upp till 20 sekunder och det är oaccepterbart lång tid.

var $parent = $('#' + masterCtrlPrefix + leftContentPrefix + 'GridViewUnits').parent(); var gridView = $('#' + masterCtrlPrefix + leftContentPrefix + 'GridViewUnits').clone(); ..loop... gridView.find('img#categoryImg' + item.Id).attr('src', item.CategoryIconSrc).attr('alt', item.CategoryIconAlt).attr('title', item.CategoryIconAlt); ...slut på loop... $parent.html(gridView);

Parent är gridview-tabellens pappa. gridView är en kopia av en html-tabell. I denna vill vi sen byta ut ikon, alt-text och title. Loopen går i maxfall upp till 4000 gånger, men i exemplet vi testar med körs den 1500 gånger. jQuery-manipulationen kan ta upp mot 15 sekunder... Är det dumt att kedja ihop attr-setters:arna, eller är det nåt annat som ser skumt ut? Vår tidtagning är rätt rudimentär men det känns som det är nåt i loopen som är en av bovarna bakom tidsåtgången.

Tacksam för hjälp!

Visa signatur

www.uu.se - some kind of university | www.hirr.org.uk - ain't no mountain high enough | www.bajenfans.se

Permalänk
Medlem

Vet inte ifall det hjälper, men prova att skicka in ett objekt med attribut till .attr() istället för flera anrop.

gridView.find('img#categoryImg' + item.Id).attr({ "src": item.CategoryIconSrc, "alt": item.CategoryIconAlt, "title": item.CategoryIconAlt });

Permalänk
Medlem

Det som jag ser som skule kunna ta tid är att den måste leta upp objekt varje gång raden körs i loopen, hade du haft den sparad som en array innan loopen börjar tror jag du hade kunnat dra ner tiden ganska ordentligt.

Svårt att säga också utan att se mer av koden, item funderar jag på exempelvis och hur loopen är definierad överhuvudtaget.

Du hade kanske kunnat vända på det och göra loopen på detta sättet?

gridview.find('.klasssomallabildernahar').each(function(){ //Allt möjligt du gör i din loop $(this).attr({ "src": item.CategoryIconSrc, "alt": item.CategoryIconAlt, "title": item.CategoryIconAlt }); });

Sedan får du kanske anpassa resten av koden en del, men du slipper iaf biten där den letar upp objektet ur gridview i loopen.

Mvh

Visa signatur

AMD Ryzen R9 3900X | Gigabyte Aorus Ultra X570 | Corsair 64GB | RTX 3080 Ti

Permalänk
Medlem

Börja med att kommentera bort raden med gridView.find inuti loopen och återkom med tidsresultat.
Återkom också med resultat om hur lång tid det tar i IE resp. Chrome. Borde skilja ca 50 %.

Jag vill absolut se hur din for-loop ser ut (eller vad det nu är för en loop). Den är allra viktigast.

Om det skulle vara raden gridView.find så går den att optimera mycket, men en sak i taget...

Permalänk

Tack för svaren! Återkommer när jag har koden tillhands, just nu kommer jag inte åt den.

Det vi vet är att kommenterar vi bort find-raden går skriptet allt mellan 6-15 sekunder snabbare, så nåt lurt är det med den. Jag antog att det var nåt problem med att varje rätt img-element måste hämtas tre gånger för attr-kedjan att få effekt, så optimera den går säkert, det var därför jag frågade här innan jag ens gav mig på det

Det är bara Firefox som klagar på "unresponsive script", men det kanske beror på att den per default är striktare med felmeddelanden?

Visa signatur

www.uu.se - some kind of university | www.hirr.org.uk - ain't no mountain high enough | www.bajenfans.se

Permalänk
Medlem

OK, en första viktig optimering är att inte skapa ett nytt jQuery-objekt för varje iteration. Måste ni förresten stödja IE6 eller räcker IE7?

// ...loop... (behöver se denna loop och hur ni tar fram item) var el = document.getElementById('categoryImg' + item.Id); el.setAttribute('src', item.CategoryIconSrc); el.setAttribute('alt', item.CategoryIconAlt); el.setAttribute('title', item.CategoryIconAlt); // ...slut på loop...

Anledningen till att detta är snabbare än att använda jQuery, är främst för att du skapar ett nytt jQ-objekt vid varje iteration (<= 4000 gånger?). Det äter prestanda.

Notera dock att jag inte använder en kopia av gridView utan ändrar direkt i DOM, vilket orsakar tre reflows per iteration (en reflow är när webbläsaren måste rita om sidan på skärmen). Det vore bättre med något sådant här:

var gridView = document.getElementById(masterCtrlPrefix + leftContentPrefix + 'GridViewUnits'), gridViewParent = gridView.parentNode, gridViewClone = gridView.cloneNode(true), trLength = gridViewClone.childNodes[0].childNodes.length; // T.ex. antal TR i denna HTML: <table><tbody><tr> // Ta bort gridView från DOM så att webbläsaren inte behöver ha båda i minnet gridViewParent.removeChild(gridView); for(var i = 0; i < trLength; i++){ var tr = gridView.childNodes[0].childNodes[i], el = tr.childNodes[0].childNodes[0]; // T.ex. en IMG i denna TR:s HTML: <tr><td><img> // Eventuellt behövs här en loop till för att iterera igenom alla TD inuti denna TR // Kommentera i så fall fram följande // for(var k = 0; k < tr.childNodes.length; k++){ // var td = tr.childNodes[k], // el = td.childNodes[0]; el.setAttribute('src', item.CategoryIconSrc); el.setAttribute('alt', item.CategoryIconAlt); el.setAttribute('title', item.CategoryIconAlt); // } } // Skicka gridView tillbaka till webbläsaren gridViewParent.appendChild(gridView);

Rekommenderar W3Schools tydliga instuktioner till att manipulera DOM-trädet: XML DOM Tutorial

OBS! Koden ovanför är helt tagen ur huvudet... garanterat otestad, säkert felstavad också.

Permalänk

Hej igen! Eftersom jag själv avskyr när folk man försöker hjälpa bara glömmer bort tråden (vilket är precis vad jag råkade göra) så tänkte jag bara uppdatera med hur det gick. Jag är inte involverad i just den kodsnutten längre men de löste det genom att köra vanilla elementmanipulering på tabellen vilket fick ner tiden avsevärt.

Tack ni tre!

Visa signatur

www.uu.se - some kind of university | www.hirr.org.uk - ain't no mountain high enough | www.bajenfans.se