[JS] Dynamisch javascript bestand laden

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Voor een webapplicatie wil ik een functie maken die dynamisch JavaScipt bestanden kan inladen. Die functie is al geschreven en staat een paar regels hieronder. Stel dat ik een simpel test bestand wil inladen dan kan ik dat via het volgende stukje code doen: "includeJS('/static/javascript/TestClass.js');". De inhoud van het JavaScript bestand staat een paar regels hieronder.

De functie maakt een nieuw <script> tag aan en zet de attributen "type" (waarde: "text/javascript") en "src". Attribute "src' bevat de waarde die meegegeven wordt als de functie aangeroepen wordt (bv.: "/static/javascript/Bestand.js"). Na het aanmaken van de tag wordt deze in de <head> tag van de pagina geplaatst als hij nog niet bestaat. Hetzelfde JavaScript bestand zal nooit twee keer als element binnen de <head> tag geplaatst worden.

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
function includeJS(src) {
    
    
    var node, nodeHead;
    var alreadyIncluded = false;
    
    nodeHead = document.getElementsByTagName('head')[0];
    
    
    // Walk through each "script" element within the header of the page.
    for (var i = 0; i < nodeHead.getElementsByTagName('script').length; i++) {
        node = nodeHead.getElementsByTagName('script').item(i);
        
        // Check if attribute "type" exists and is set to "text/css".
        if ((node.attributes.getNamedItem('type') === null) || (node.attributes.getNamedItem('type').value != 'text/javascript')) {
            continue;
        }
        
        // Check if attribute "src" exists.
        if (node.attributes.getNamedItem('src') === null) {
            continue;
        }
        
        // Check if the found JS file is the same as the JS file to be included.
        if (node.attributes.getNamedItem('src').value == src) {
            alreadyIncluded = true;
        }
    
    }
    
    
    // Do nothing if the file has been included before.
    if (alreadyIncluded === true) {
        return;
    }
    
    
    // Create a new script element.
    var element = document.createElement('script');
    element.setAttribute('type', 'text/javascript');
    element.setAttribute('src', src);
    
    
    // Add it to the page header.
    nodeHead.appendChild(element);
    
    
}



Inhoud van "/static/javascript/TestClass.js":

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
function TestClass() {
    
    var somethingSomething = "anything";
    
    this.echoSomething = function() {
        
        window.alert(somethingSomething);
        
    };
    
}


Echter, volgend stukje faalt. De melding "TestClass is not defined" komt tevoorschijn als "window.alert(TestClass)" wordt uitgevoerd terwijl de <script> tag wel goed toegevoegd is aan de <head> tag. Als ik de functie "includeJS" aanpas en na de laatste regel ("nodeHead.appendChild(element);") binnen die functie de code "window.alert('');" toevoeg werkt het wel. Ik krijg dan de inhoud van de TestClass op mijn scherm ge-alert.

JavaScript:
1
2
3
4
5
6
function test() {
    
    includeJS('/static/javascript/TestClass.js');
    window.alert(TestClass);
    
}


Waar het precies aan ligt weet ik niet, maar ik denk dat de toegevoegde window.alert aan de IncludeJS functie ervoor zorgt dat er een delay is en de browser zo de tijd krijgt om het JavaScript in te laden. Kan iemand dit bevestigen en als dit inderdaad het probleem is, hoe kan ik dit dan het beste oplossen? Een setTimeout gebruiken naar een functie die controleert of de klasse bestaat zou dan een optie kunnen zijn, maar er moet een betere manier zijn. Een while loop die constant checkt of de klasse bestaat is erg CPU intensief, dus dat is niet echt een optie.

Het probleem is niet browser specifiek en de gebruikte code is volgens JSLint ook correct. "document.createElement('script')" vervangen door een "document.write" regel om zo een script tag in de body van de pagina te schrijven lost het probleem ook niet op.

Hopelijk kan iemand mij advies geven. Bedankt voor elke reactie :) .

[ Voor 0% gewijzigd door Verwijderd op 19-01-2010 14:01 . Reden: typo ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-09 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zet een onload op de script tag

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 18-09 16:28
Je zult toch moeten achterhalen wanneer het script klaar is met laden voordat je er iets mee gaat doen. Of de onload op de script-tag xbrowser werkt weet ik niet, dat zou je moeten proberen, of kijken naar hoe andere libraries dit xbrowser afhandelen.

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

onload op de script-tag werkt vziw niet crossbrowser. Gecombineerd met een onreadystatechange kom je echter wel een eind, maar (oudere?) webkits vallen dan meen ik nog buiten de boot. Kijk inderdaad eens hoe andere libraries of bijvoorbeeld google.load() het doet.

Intentionally left blank


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Bedankt voor alle reacties, ik ga het eens uitzoeken.

Acties:
  • 0 Henk 'm!

  • CH4OS
  • Registratie: April 2002
  • Niet online

CH4OS

It's a kind of magic

Is het niet verstandiger om met PHP of een van de andere serverside talen te bepalen welke JS bestanden geladen moet worden? :? Heb je ook een stuk zekerheid dat de JS geladen wordt, zoals Crisp al aangeeft.

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

Als je alles in eigen beheer hebt zou je het te laden bestand natuurlijk gewoon een functiecall kunnen laten doen om 'zich te melden'. Eventueel zou je nog met een timeout kunnen werken om de include als 'failed' te laten beschouwen. Als alternatief zou je inderdaad kunnen 'pollen' op de beschikbaarheid van een bepaalde variabele of functie.

Ik heb diverse libraries (waaronder YUI, de Google API en jQuery) bekeken, en die gebruiken allemaal de combo onload/onreadystatechange op basis van gedetecteerde browser (met eventueel polling fallback voor oude webkit-based browsers). Ik heb daar zelf ook nog geen goed alternatief voor kunnen vinden, behalve misschien XHR ism eval(), maar dan moet de JS wel van hetzelfde domein geladen worden...

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • krvabo
  • Registratie: Januari 2003
  • Laatst online: 19-09 22:02

krvabo

MATERIALISE!

crisp schreef op woensdag 20 januari 2010 @ 00:31:
Als je alles in eigen beheer hebt zou je het te laden bestand natuurlijk gewoon een functiecall kunnen laten doen om 'zich te melden'. Eventueel zou je nog met een timeout kunnen werken om de include als 'failed' te laten beschouwen. Als alternatief zou je inderdaad kunnen 'pollen' op de beschikbaarheid van een bepaalde variabele of functie.
Wat dat betreft is het jammer dat je rekening moet houden met oudere browsers, want wellicht had de TS anders eens kunnen kijken naar workers. Die hebben dan weer wel als nadeel dat ze de DOM niet kunnen aanspreken.. Echter is het alleen beschikbaar in FF3.5+, Safari 4 en recente Chrome-uitvoeringen. Hierin kun je ook gebruikmaken van een ready-call naar de parent.

Dit alles natuurlijk gewoon als informatie. Voordat we zoiets kunnen verwachten in IE zijn we wel weer een jaar of 5-6 verder. Voor het huidige probleem is je ready-call suggestie denk ik het beste en minst obstrusive.

Pong is probably the best designed shooter in the world.
It's the only one that is made so that if you camp, you die.


Acties:
  • 0 Henk 'm!

  • pieturp
  • Registratie: April 2004
  • Laatst online: 18-09 15:56

pieturp

gaffa!

GJtje schreef op woensdag 20 januari 2010 @ 00:19:
Is het niet verstandiger om met PHP of een van de andere serverside talen te bepalen welke JS bestanden geladen moet worden? :? Heb je ook een stuk zekerheid dat de JS geladen wordt, zoals Crisp al aangeeft.
Ja, maar 't kan ook wel fijn zijn je user feedback te geven als je echt véél JS gaat laden. Een klein progressbarretje heeft zo z'n voordelen. Zeker als je er voor zorgt dat de browser deze files cached voor volgende bezoeken ;)

Vergeet dan trouwens niet een kleine timeout voor de callbacks, zodat de browser wel aan de (re-)paints toekomt, zoals ik laatst 'ns was vergeten... |:(

... en etcetera en zo


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Bedankt voor alle reacties, zeer informatief.

In de toekomst, wanneer worker-compatible browsers mainstream zijn, is dat een goede oplossing. Voor nu heb ik het opgelost door het javascript bestand dat geladen wordt een functie binnen de laad klasse aan te roepen om zich zo 'te melden'. Zeker niet de mooiste oplossing, maar met de kennis en tijd die ik nu heb ben ik er voor nu tevreden mee.
Pagina: 1