[JS] js-bestanden includen als DOM geladen is

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Ik ben zo stom geweest om mijn site te ontwikkelen in Firefox en pas op het laatste moment te controleren in IE. Wat blijkt nu: als ik de site open in IE 4, 5 of 6 (op windows), krijg ik een error:
Internet Explorer cannot open the website http://192.168.0.3/test
Operation aborted.
Na enig Googlen kwam ik erachter dat het een bug betreft. Onder andere Gary Haran legt uit:
Internet Explorer doesn’t like scripts appending elements to the existing DOM [before the tag has been closed] When Internet Explorer fails it fails spectacularly by shutting down the script engine and aborting page rendering. One way to circumvent the error is to wait till the entire page DOM has been rendered. You can do that with window.onload.
In de head van mijn site roep ik 1 javascript bestandje aan: index.js. In dit bestand worden alle andere javascriptjes geinclude met de volgende code:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function include(sources) {
  var head = document.getElementsByTagName('head')[0];
  for (i in sources) {
    var script = document.createElement('script');  
    script.type = 'text/javascript';
    script.src = sources[i];
    head.appendChild(script);
  }
}

include([
  'system/dom.js', 
  'system/tools.js', 
  'system/ajax.js'
]);

Dit werkt dus perfect behalve in IE 4, 5 en 6, zoals ik het begrijp omdat de head-tag nog niet is afgesloten op het moment dat ik script-tags als child eraan wil hangen. Zoals de tip hierboven aangaf, moet ik wachten totdat de hele DOM gerendered is, dus:
JavaScript:
1
2
3
4
5
6
7
window.onload = function () {
  include([
    'system/dom.js', 
    'system/tools.js', 
    'system/ajax.js'
  ]);
}

Maar dit werkt niet. De bestanden worden nu niet geinclude. (Ik weet dit, omdat als ik een alert() in bv. dom.js zet, deze niet omhoog komt als ik de pagina laadt). Mijn vraag is: wat doe ik verkeerd?

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Mag ik vragen waarom je dit überhaupt wilt? Als je gewoon <script src='...' > tags gebruikt worden scripts ook pas ingeladen als de rest van de pagina klaar is.

Verder zou je body.onload kunnen proberen.

TabCinema : NiftySplit


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Bozozo schreef op woensdag 30 april 2008 @ 18:30:
Mag ik vragen waarom je dit überhaupt wilt? Als je gewoon <script src='...' > tags gebruikt worden scripts ook pas ingeladen als de rest van de pagina klaar is.
Since when?

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Tofu
  • Registratie: Maart 2003
  • Laatst online: 05-10-2024
Bozozo schreef op woensdag 30 april 2008 @ 18:30:
Mag ik vragen waarom je dit überhaupt wilt? Als je gewoon <script src='...' > tags gebruikt worden scripts ook pas ingeladen als de rest van de pagina klaar is.

Verder zou je body.onload kunnen proberen.
Misschien omdat je dan zo dynamisch kan bepalen welke libraries je al dan niet nodig zal hebben. Al vrees ik dat het laden van de pagina nu een stuk langer zal duren (JS worden pas later binnengehaald?)

Acties:
  • 0 Henk 'm!

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

Als je een zoekactie doet op 'ondomready' dan denk ik dat je er wel uit moet komen :)

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Tofu schreef op woensdag 30 april 2008 @ 18:43:
[...] Misschien omdat je dan zo dynamisch kan bepalen welke libraries je al dan niet nodig zal hebben.
Juist :)
Al vrees ik dat het laden van de pagina nu een stuk langer zal duren (JS worden pas later binnengehaald?)
Volgens mij niet. Hoe je het ook doet, een HTML pagina wordt van boven naar beneden gerendered, volgens mij. De enige vertraging zou daar zitten, dat je aparte bestandjes van de server haalt, maar dat is imho verwaarloosbaar.

Ik dacht, laat ik het meteen netjes oplossen:
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
function addLoadEvent(func) {
  var oldOnload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  }
  else {
    window.onload = function() {
      oldOnload();
      func();
    }
  }
}

function include(sources) {
  var head = document.getElementsByTagName('head')[0];
  for (i in sources) {
    var script = document.createElement('script');  
    script.type = 'text/javascript';
    script.src = sources[i];
    head.appendChild(script);
  }
}

addLoadEvent(function () {
  include([
    'system/dom.js', 
    'system/tools.js', 
    'system/ajax.js', 
    'system/collapse.js',
    'system/fade.js',
    'system/images.js'
  ]);
});

Maar dit werkt ook niet (.js bestanden worden niet ingeladen?!) en ik heb geen idee waarom. addLoadEvent is een functie waarvan ik weet dat 'ie werkt (ik gebruik hem al tijden).

Over ondomready: dat is een Mootools specifieke functie. Is wel van te leren en na te bouwen natuurlijk, maar is het wel nodig? In principe is de DOM toch geladen op window.onload? En dan zou je op dat moment toch script-tags moeten kunnen toevoegen? Dat zou imho al op head.onload moeten kunnen (als die zou bestaan).

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

ondomready is niet een specifieke functie; het is een vrij generieke naam voor een event dat wordt getriggerd wanneer de dom geladen is. Mootools heeft er inderdaad een impelmentatie van. Het probleem met window.onload is dat die pas getriggerd wordt als ook alle binary content van de pagina geladen is; dus ook al je plaatjes. window.onload komt altijd pas ná ondomready, en soms pas veel later. Dat is vaak niet ideaal.

[ Voor 8% gewijzigd door eamelink op 30-04-2008 19:07 ]


Acties:
  • 0 Henk 'm!

  • Bozozo
  • Registratie: Januari 2005
  • Laatst online: 20-02 16:10

Bozozo

Your ad here?

Willekeurige suggestie: probeer eens om ze toe te voegen aan de body ipv aan de head.

Kun je dit niet gewoon serverside doen trouwens?

TabCinema : NiftySplit


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
eamelink schreef op woensdag 30 april 2008 @ 19:06:
ondomready is niet een specifieke functie; het is een vrij generieke naam voor een event dat wordt getriggerd wanneer de dom geladen is. Mootools heeft er inderdaad een impelmentatie van. Het probleem met window.onload is dat die pas getriggerd wordt als ook alle binary content van de pagina geladen is; dus ook al je plaatjes. window.onload komt altijd pas ná ondomready, en soms pas veel later. Dat is vaak niet ideaal.
Dat wist ik niet, en daar ga ik dus wat mee doen. Wat echter blijft staan is de vraag waarom de js-bestanden met de code hierboven niet worden ingeladen. Kan iemand mij daar een antwoord op geven?

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Tofu
  • Registratie: Maart 2003
  • Laatst online: 05-10-2024
Reveller schreef op woensdag 30 april 2008 @ 18:59:
[...]
Volgens mij niet. Hoe je het ook doet, een HTML pagina wordt van boven naar beneden gerendered, volgens mij. De enige vertraging zou daar zitten, dat je aparte bestandjes van de server haalt, maar dat is imho verwaarloosbaar.
Maar je moet eens dit lezen. Blijkbaar worden files soms parallel en soms sequentieel geladen. Als je op jouw manier files include gaan die misschien pas geladen worden na het uitvoeren van die functie, en dan vermoedelijk nog elk na elkaar en niet tegelijkertijd?

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Nu heb ik dus weer een nieuw probleem. Heb nu dit (in index.js):
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
function DomReady(fn) {
  if (document.addEventListener) {
    document.addEventListener("DOMContentLoaded", fn, false);
  }
  else {
    document.onreadystatechange = function(){readyState(fn)}
  }
}

function readyState(fn) {
  if (document.readyState == "interactive") {
    fn();
  }
}

function include(sources) {
  var head = document.getElementsByTagName('head')[0];
  for (i in sources) {
    var script = document.createElement('script');  
    script.type = 'text/javascript';
    script.src = sources[i];
    head.appendChild(script);
  }
}

function includeJS() {
  include([
    'system/dom.js', 
    'system/tools.js', 
    'system/ajax.js'
  ]);
}

window.onDomReady = DomReady;

window.onDomReady(includeJS);

In het bestand system/tools.js zit een functie genaamd "box". De pagina waar ik index.js in aanroep, ziet er (verkort) als volgt uit:
HTML:
1
2
3
4
5
6
7
8
9
10
<html>
  <head>
    <script type="text/javascript" src="system/index.js"></script>
  </head>
  <body>
    <script>
      box(foo, bar);
    </script>
  </body>
</html>

Als ik deze pagina nu laadt, zegt Firebug "box is not defined". Als ik het goed begrijp, wordt eerst de DOM (van de html pagina hierboven) ingeladen. De render engine komt een aanroep naar de functie "box" tegen, maar omdat de js-bestanden pas na het laden van de DOM ingeladen worden, is deze functie nog niet gedefinieerd. Dit is een beetje een eindeloze cirkel. Heeft iemand een oplossing?

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Blaise
  • Registratie: Juni 2001
  • Niet online
Ik zou stoppen met al die dynamische grappen en de boel serverside regelen. Dat is een stuk robuuster, je hebt geen last van dependencies die in de soep lopen door het asynchrone laden, en het werkt in alle browsers.

Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
JavaScript:
1
2
3
4
5
6
function LoadScript( url )
{
    document.write( '<script type="text/javascript" src="' + url + '" onerror="alert(\'Error loading \' + this.src);"><\/script>' ) ;
}

LoadScript( '../fckconfig.js' ) ;


Uit FCKeditor, paar keer gebruikt en doet volgens mij wat je wilt op de meest simpele manier... :)

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Blaise schreef op woensdag 30 april 2008 @ 21:47:
Ik zou stoppen met al die dynamische grappen en de boel serverside regelen. Dat is een stuk robuuster, je hebt geen last van dependencies die in de soep lopen door het asynchrone laden, en het werkt in alle browsers.
Ik ben inmiddels ook bijna op dat punt...
Cartman! schreef op woensdag 30 april 2008 @ 21:52:
JavaScript:
1
2
3
4
5
6
function LoadScript( url )
{
    document.write( '<script type="text/javascript" src="' + url + '" onerror="alert(\'Error loading \' + this.src);"><\/script>' ) ;
}

LoadScript( '../fckconfig.js' ) ;


Uit FCKeditor, paar keer gebruikt en doet volgens mij wat je wilt op de meest simpele manier... :)
...maar nog snel even kijken of dit werkt (hoewel het sowieso al ranziger is dan via de DOM)

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 11:19

crisp

Devver

Pixelated

Dit werkt toch prima in IE6:
HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!doctype html>
<html>
<head>
<script type="text/javascript">

var s = document.createElement('script');
s.type = 'text/javascript';
s.src = 'bla.js';
document.getElementsByTagName('head')[0].appendChild(s);

</script>
</head>
<body>
</body>
</html>

Het gaat fout op het moment dat ik een <base href> toevoeg vanwege de manier waarop IE < 7 het base-element behandeld. Dat is overigens op te lossen door een (non-standard) close-tag op te nemen, bijvoorbeeld met conditional comments:

HTML:
1
<base href="http://localhost/"><!--[if lte IE 6]></base><![endif]-->


window.onload en DOMContentLoaded zijn inderdaad niet nuttig als je je scripts toch nodig hebt voordat deze events plaatsvinden. document.write is een oplossing, maar alleen voor de gevallen waarbij je scripts tijdens het parsen toevoegd, daarna werkt het niet meer.

Overigens over asynchroon/synchroon: in de meeste browsers worden scripts synchroon geladen. In bepaalde bèta-browsers worden op dit moment scripts soms wel asynchroon (vooruit) geladen maar in ieder geval synchroon in het document geparsed en verwerkt. Enige uitzondering is vziw het defer attribuut in IE wat echt zorgt voor asynchrone verwerking (en ook gebruikt wordt om het DOMContentLoaded event te imiteren in libraries).

Intentionally left blank

Pagina: 1