Jednoduchý loader v JavaScriptu

Často je potřeba načítat části javascriptu dynamicky, google má na to pěknou knihovnu zde. Klidně použijte, já ale rád dělám věci po svém, mám pak přehled a něco málo se naučím.

Jak řeším moduly js na straně servru

Používám v apachi mod_rewrite a v accessu mám definovaná pravidla, která přesměrují na index.php chybějící požadavky na js soubor s moduly. Jsem tedy schopen za běhu vygenerovat buď jednotlivý modul anebo balík modulů.

Kostra loaderu

Začněme tím, že definujeme kostru třídy Loader v loader.js.

function Loader() 
{
// objekt do ktereho budem vkladat scripty s novymi moduly
var appendTo = document.getElementsByTagName('body')[0];
var url = "/js/"; // url ze ktere se maji moduly nacitat
var onReady = []; // zde si ulozime vsechny callbacky
var loaded = {}; // zde si postupne ulozime vsechny jiz nahrane moduly
this.load = function(modules,onload)  {};
this.ready = function(modules,onready) {};
var isReady = function(modules) {};
var isReadyModule = function(module) {};
var init = function() {};
init();
}

Inicializace loaderu – metoda init

loader připojte pokud možno jako 1. script v dokumentu a inicializujte ho až po načtení obsahu stránky.

(function(){
self["loader"] = new Loader();
})();

ve funkci init nejdřív zjistíme, zda nějaký skript neobsahuje adresu, kterou používáme pro načtení js modulů, pokud ano, rozparsujeme a přidáme do objektu loaded;

interní funkce init by mohla vypadat následovně

var init = function()

var modules, src, match, script = document.getElementsByTagName('script'); 
var mRe = new RegExp(url.replace(///g,'\/') + '([^.]*)@.*.js$');
for(var i = 0; i < script.length; i++)
{
src = script[i].src;
match = src.match(mRe);
if (match !== null && match.length == 2)
{
modules = match[1].split(','); // oddelovac modulu v adrese
for(var j = 0; j < modules.length; j++)
loaded[modules[j]] = true;
}
}
};

Metoda isReadyModule

tuto metodu použijeme pro testovaní „připravenosti“ modulu bude opravdu jednoduchá.

var isReadyModule = function(module)
{
return loaded[module] !== undefined;
};

Metoda isReady

tato metoda otestuje celý balík modulů, projde pole modulů a „podívá se“, zda je modul v objektu loaded, který používám jako asociativní stavové pole.

var isReady = function(modules)
{
var ready = true;
for(var i = 0; i < modules.length; i++)
if ( loaded[modules[i]] === undefined )
{
ready = false;
break;
}
return ready;
};

Metoda ready

public metoda ready se stará o spustí onReady, pokud jsou moduly načteny, jinak přidá do pole onReady, pro znovupoužitelnost vracím true, pokud jsou moduly připraveny, jinak false

this.ready = function(modules, onready)
{
if (isReady(modules))
onready();
else
{
onReady.push([modules,onready]);
return false;
}
return true;
};

Metoda load

nejsložitější ze všech použitých metod, musí se postarat o načtení modulů, a spouštění callbacků po načtení. Určitě doporučuji rozdělit na private metody.

Ve script.onload se po načtení scriptu zavolá funkce, která nastaví všechny needed moduly do stavu načteno, následně se zkontrolují všechny onReady prvky, pokud mají načtené moduly, které jsou na indexu 0 spustím callback z indexu 1 a nastavím na false, pro zamezení dalších spouštění. Možná by se po iteraci hodilo vyčistit pole, vyhodit všechny onReady[i], které budou false. Otázka zní, zda to bude mít přínos. Pro malé projekty spíš ne, pro molochy určitě. Představte si, jak procházíte pole se 10 000 prvky a z nich většina je false, plýtvá se cykly a narůstají paměťové požadavky.

this.load = function(modules, onload)
{
if (this.ready(modules, onload)) return true;
else
{
var script,needed = [];
for(var i = 0; i < modules.length; i++ )
if (!isReadyModule(modules[i]))
needed.push(modules[i]);
script = document.createElement('script');
script.type = 'text/javascript';
script.onload = function()
{
for(i = 0; i < needed.length; i++)
loaded[needed[i]] = true;
for(i = 0; i < onReady.length; i++)
if (onReady[i] && isReady(onReady[i][0]))
{
onReady[i][1]();
onReady[i] = false;
}
};
script.src = url + needed.join(',') + '.js';
appendTo.appendChild(script);
}
};

loader.js ke stažení

Stáhněte si loader.js a vyzkoušejte. Určitě vás napadne, jak rozšířit o další funkčnosti, třeba doporučuji metody loadCss anebo loadování js modulů včetně css, pokud vyžadují a pod.