... aniž by se zasekl prohlížeč.
V práci jsem řešil jeden velký problém. Potřeboval jsem zpracovat mnoho JavaScriptových objektů a ne zrovna malých. Doufám, že nebude vadit, když se podělím s malým know how, které vykonávám pro firmu :-) Ale třeba si to přečte někdo, kdo mi poradí jiný a lepší způsob.
Hlavní problém je v tom, že uživatel vykoná pro něj obyčejnou akci a já (JavaScript) musím na pozadí stránky provést složité zpracování. V tuto chvíli, ač se to tak nezdá, je potřeba hrát na rychlost skriptů, které se provádí pouze na straně prohlížeče.
Např. tedy, uživatel klikne na
označit vše v ul>li seznamu A, který má třeba 10 elementů a v seznamu B s 5000 elementy označit ty elementy, které obsahují v atributu rel hodnotu z označeného elementu v seznamu A.
Používám pro svojí práci knihovnu
jQuery a musím říct, že funkcí
each cesta fakt nevede. Každá tisícina vteřiny je pak znát a to hlavně, pokud necháte vše zpracovat jak se říká "na jedno našlápnutí" :-)
On je taky rozdíl v použitém prohlížeči, protože třeba Firefox si při spuštění takových skriptů je schopný vzít i dalších 300 MB paměti a 30% navíc na procesoru.
Další nepříjemná věc je ta, že takové skripty děláme hlavně pro klienty, kterým moc nevysvětlíme, že je to normální, když kliknou na jeden "odkaz" a najednou se jim začne zahřívat procesor jak cip a k tomu jim v prohlížeči vyskočí dotaz zda počkat na zpracování skriptu nebo skript ukončit a ještě k tomu se jim zobrazí, že prohlížeč neodpovídá :-D
No takže jediný řešení, který mě napadlo je zpracovat vždy kousek a poté zpracovat další kousek. Snažil jsem se něco vygooglit, ale nenašel jsem nikoho, kdo by toto řešil.
Výsledek je několik funkcí v JS a jQuery jako takovém, ale hlavně s tím, že vždy jsem dopředu věděl jak budou zpracovávané objekty velké a kolik toho bude.
Například asi takto:
(function(){
$.selectLinks = {
all: function(){
this.nextObject(0); // spustíme první element seznamu
},
nextObject: function(objectIndex){
// ukončíme, protože neexistuje žádný element s tímto "indexem"
if($("ul.list li[class!='active']:eq("+objectIndex+")").length == 0){
return false;
}
var thisObj = $("ul.list li[class!='active']:eq("+objectIndex+")");
// nějaké další akce v JS
if(objectIndex % 100 == 0){ // modulo na každý stý záznam a následné zajištění pozastavení zpracovávání v prohlížeči na půl vteřiny
window.setTimeout(function(){
$.selectLinks.nextObject((objectIndex+1));
}, 500);
}else{
$.selectLinks.nextObject((objectIndex+1));
}
}
};
})(jQuery);
Neříkám, že skripty se zrychlí nebo budou méně náročné na počítač, ale důležité v tomto případě je hlavně nedát najevo klientům, že vznikla nějaká chyba s jejich draze zaplaceným systémem.
Výše uvedený kód jsem tu vyhaluzil jen tak na první našlápnutí, takže ani nemusí v podstatě fungovat, nicméně důležité na tom vidět je.
Hlavní a myslím si, že nejjednodušší je pouštět jednu funkci rekurzivně dokud je to možné s tím, že občas počkáme pomocí setTimeout na nové spuštění, k tomu klidně stačí půl vteřiny i méně.
V mém případě na projektu v práci jde o daleko složitější skripty, které zahrnují spoustu jiných věcí.
Budu rád, když někdo hodí koment a třeba mě i přiučí lepším věcem.
Ave já
PS: Jo a kdyby někdo nevěděl, spouštěl bych to $.selectLinks.all();