A JavaScript nyelv alapból nem tartalmaz “include” nyelvi lehetőséget, vagyis egy másik JavaScript fájl behívását és értelmezését nem teszi lehetővé JavaScriptből. Ez az esetek többségében nem is okoz gondot, de azért vannak olyan körülmények, amikor jól jönne. Van rá lehetőség.

Két helyzetet emelnék ki, melyek indokolják egy JavaScript fájl betöltését. Az egyik, amikor “on-demand”, azaz akkor szeretnénk betölteni egyes JavaScript darabokat, amikor azokra valóban szükség van. Ezt a sávszélesség minimalizálása indokolhatja, esetleg egyéb extrém esetek. A másik az a cross domain kommunikáció, amikor az adott domaintől eltérő címről szeretnénk adatokat betölteni. Adatkommunikációra illik JSON/XML AJAX kéréseket használni, de mivel ezek csak az aktuális domain fele indulhatnak, mégis szükség lehet a scriptek segítségével történő kommunikációra.
A JavaScript behívása többféleképpen megoldható, egy szép megoldás a HTML dokumentum “head” részébe dinamikusan felvenni egy hivatkozást (lehet még például “document.write()”-tal is szórakozni, de az ronda). Ez a következőképpen vitelezhető ki:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function jsInclude(url) { // a fejléc elem megkeresése var head = document.getElementsByTagName('head').item(0); // egy új <script> elem létrehozása és felparaméterezése var js = document.createElement('script'); js.setAttribute('language', 'javascript'); js.setAttribute('type', 'text/javascript'); js.setAttribute('src', url); // a <script> elem hozzáadása a fejléc elemhez head.appendChild(js); return false; } |
A DOM getElementsByTagName függvényével megkeressük a fejléc elemet (az elsőt, de ugye csak egy van, és az mindenképpen van), létrehozunk egy “script” elemet, felparaméterezzük, majd hozzáadjuk. Ekkor “egyből” betöltődik és le is fut (amint befejeződik az adott JavaScript kód blokk futása).
Adatot átvenni távolról viszonylag trükkösen lehet. Mivel nem tudjuk, hogy mikor érkezik meg a válasz (ugyanúgy, mint egy AJAX kérésnél), ezért aszinkron módon kell kezelnünk az adatkérést. Amikor megérkezik és lefut a JavaScript, nincs lehetőségünk egy függvény lefuttatására (ahogyan AJAX esetén van), és egy változóba sem tudjuk beletenni a választ. Ezeket a feladatokat tehát abba a kódba kell tennünk, amit behívunk. Ezt aztán már lehet variálni, az egyik megoldás egy függvényhívás kódjának elhelyezése lehet a behívott JavaScriptben. Például:
1 2 3 4 5 | function callback(response) { alert(response); } jsInclude("http://example.net/example.script?callback=callback&value1=3&value2=4"); |
Egy lehetséges PHP kód:
1 2 3 4 5 6 7 | $callback = $_GET["callback"]; $value1 = $_GET["value1"]; $value2 = $_GET["value2"]; $response = $value1 * $value2; header('Content-type: text/javascript'); echo "$callback(\"$response\"); |
Fontos, hogy ezzel a módszerrel megvalósított távoli eljáráshívásokban számos biztonsági és üzemeltetési kockázat rejlik. Az egyik gond, hogy szinte bárki meghívhatja ilyen módon az általunk elkészített kis <script> szolgáltatást, és IP címre sem korlátozhatunk, mivel a kérés jellemzően a felhasználó böngészője felől érkezik, ami gyakorlatilag bármely IP címmel rendelkezhet. A fenti kis példakód kódja sem áll a helyzet magaslatán, illene például megvizsgálni, hogy a callback tényleg valamilyen függvénynévszerűt tartalmaz, és nem egyéb JavaScript kódot (ami simán lefut). Ennek direkt kockázata ugyan nincsen, de nem árt inkább túlbiztosítani magunkat.
Végül megemlíteném még, hogy a különböző JavaScript függvénykönyvtárak sokszor alapból kínálnak a fenti “jsInclude” függvényhez hasonló megoldást, vagy pedig létezik kiegészítő hozzájuk, mely lehetőségeiben többet nyújt ennél, számos böngészőben tesztelt, és a legjobb megoldást próbálja meg nyújtani.
S hogy mit lehet kihozni egy ilyen kommunikációból? Erre jó példa a Google Feed API-ja.
“lehet még például “document.write()”-tal is szórakozni, de az ronda”
Ez tisztán esztétikailag értendő, vagy vannak gyakorlati hátrányai is?
Ha az oldal már betöltődött, akkor a document.write lecseréli az oldalad tartalmát, nem pedig kiegészíti. Ez gyakorlati hátránynak mondható.
Ezzel gyakorlatilag XSS tamadhatova teszed a webszolgaltatasod. Persze ha ilyesmire van szukseged, akkor nyilvan amugy is publikusak azok az adatok, amiket igy akarsz cross domain elerni.
Ezért írtam, hogy biztonsági és üzemeltetési kockázat rejlik egy ilyen megoldásban. Egyébként megoldható biztonságosan is a dolog, pl. “aláírással” (a meghívó kap valahonnan szerver oldal felől egy egyszer használható kódot, és ezt továbbküldi a scriptnek).
Először is szeretném megköszönni Bártházi András-nak az ihletet és remélem, hogy nem haragszik, hogy egy kicsit kibővítettem a funkcióját!
Az újdonság amit tud, hogy ha a useOnce paraméter “true”, akkor megnézi, hogy van-e már ilyen url-el a fejlécben script, és ha van, akkor nem adja hozzá mégegyszer. Erre talán szükség lehet
Jó programozást mindenkinek, és íme a kód:
/*
jsInclude funkció
Leírás:
Include funkciót hajt végre az “url” argumentumban
megdott *.js fájlra. Azaz betölti az oldalra.
Argumentumok:
– url: a fájl elérési útja, amit be akarunk húzni,
– useOnce: true kell, hogy legyen, ha csak egyszer akarjuk, hogy megjelenjen
az aktuális script a weblapon belül.
Visszatérés:
– true, ha hozzáfűződött a javascript
*/
function jsInclude(url, useOnce)
{
// a fejléc elem megkeresése
var head = document.getElementsByTagName(“head”).item(0);
//kiolvassuk az összes objektumot a fejlécből
var jss = head.getElementsByTagName(“script”);
// tag számláló
var index = 0;
//Csak egyszer használható?
if(useOnce == true)
//Ha csak egyszer akarjuk használni, akkor kell keresni, hogy megvan-e
{
//Végigfutunk, hogy van-e már ilyen script behúzva
for(; (index < jss.count) && (jss.item(index).getAttribute(“src”) != url); index++);
}
//Megtaláltuk (azaz nem futott túl az “index”) vagy többször is be akarjuk húzni?
if(index == jss.count || useOnce == false)
//Nem létezik vagy többször is használható, ezért létrehozhatjuk
{
//Egy új elem létrehozása és felparaméterezése
var js = document.createElement(“script”);
js.setAttribute(“language”, “javascript”);
js.setAttribute(“type”, “text/javascript”);
js.setAttribute(“src”, url);
//A elem hozzáadása a fejléc elemhez
head.appendChild(js);
//Hozzáfűztük szóval true-t kell visszaadni
return true;
}
//Nem adódott hozzá a megadott javascript
return false;
}
robigyerek: Nem haragszom.