2009-12-18 4 views
25

J'utilise le chargement de script dynamique pour réduire la durée du chargement initial de la page. Pour m'assurer que les fonctions et les objets définis par un script sont accessibles, je dois m'assurer que le script a été entièrement chargé.Peut-on faire confiance à script.readyState pour détecter la fin du chargement de script dynamique?

J'ai développé my own Javascript library à cette fin, et donc fait beaucoup de recherches sur le sujet, en étudiant comment cela se fait dans différentes bibliothèques. Au cours d'une discussion concernant cette question, Kyle Simpson, l'auteur de LABjs, a déclaré que:

LABjs (et beaucoup d'autres chargeurs) mis à la fois "onload" et "onreadystatechange" sur tous les éléments de script, sachant que certains navigateurs un feu, et certains vont tirer l'autre ...

Vous pouvez trouver un exemple dans the current version of jQuery as of this writing, v1.3.2:

// Attach handlers for all browsers 
script.onload = script.onreadystatechange = function(){ 
    if (!done && (!this.readyState || 
    this.readyState == "loaded" || this.readyState == "complete")) { 
     done = true; 
     success(); 
     complete(); 

     // Handle memory leak in IE 
     script.onload = script.onreadystatechange = null; 
     head.removeChild(script); 
    } 
}; 

C'est l'état de l'art, mais lors de l'analyse d'un comportement étrange dans Opera 9.64, j'en suis arrivé à la conclusion que, grâce à cette technique, le rappel onload s'est déclenché trop tôt.

Je vais poster mes propres résultats en réponse à cette question, et je voudrais recueillir des preuves supplémentaires et des commentaires de la communauté.

+0

Quelqu'un trouve-t-il le code actuel dans la branche jQuery 1.x-master? On dirait qu'ils ont quitté en utilisant '.onreadystatechange' et' .onload' et les ont remplacés par des promesses? [Clicky] (https://github.com/jquery/jquery/blob/1.x-master/src/ajax.js) – Campbeln

Répondre

7

Dans Opera, la propriété script.readyState ne peut pas être approuvée. Par exemple, le readyState "loaded" peut être déclenché avant que le script s'exécute dans Opera 9.64. J'ai effectué the same test dans Opera 9.64 et Opera 10, avec des résultats différents.

Dans Opera 9.64, le gestionnaire onreadystatechange est renvoyé deux fois, une fois avant et une fois après l'exécution du script. La propriété readyState est « chargé » dans les deux cas, ce qui signifie que cette valeur ne peut pas faire confiance pour détecter la fin du chargement du script:

# Fri Dec 18 2009 17:54:43 GMT+0100 
# Opera/9.64 (Windows NT 5.1; U; en) Presto/2.1.1 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
readystatechange: loaded 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: loaded 

Dans Opera 10, le gestionnaire onreadystatechange obtient toujours tiré deux coups avec la valeur " chargé », mais les deux fois après le script couru:

# Fri Dec 18 2009 18:09:58 GMT+0100 
# Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.10 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: loaded 
readystatechange: loaded 

Ces différents comportements indiquent que onreadystatechange est pas un moyen fiable pour détecter la fin d'un chargement de script dans Opera. Comme Opera prend également en charge l'écouteur onload, cet autre mécanisme devrait être utilisé à la place. En fonction des résultats de ces tests, le paramètre onreadystatechange ne doit être utilisé que pour détecter la fin du chargement du script dans Internet Explorer et ne doit pas être défini dans d'autres navigateurs.

+0

Dans le moins, vous pouvez ignorer le premier événement. –

+2

@ Johnson Johnson qui semble maladroit, comptez-vous les événements "chargés", mais seulement dans Opera? –

3

Dans Firefox, Safari et Chrome, le gestionnaire onreadystatechange nevers est appelé.

J'ai créé un test court, la création d'un script dynamique avec seulement le jeu de gestionnaire onreadystatechange:

<script type="text/javascript" language="javascript"> 
bezen.log.info(new Date(),true); 
bezen.log.info(navigator.userAgent,true); 

// Activate logs 
bezen.log.on(); 
bezen.log.info('Test for script.readyState behavior started'); 

var script = document.createElement('script'); 
script.src = 'test1.js'; 
script.onreadystatechange = function(){ 
    bezen.log.info('readystatechange: '+script.readyState); 
}; 
document.body.appendChild(script); 
bezen.log.info('Added script with onreadystatechange handler'); 
</script> 

je fis le test sur un fichier local dans Firefox 2, Firefox 3, Firefox 3.5, Safari 3, Safari 4 et Chrome 3, et ont obtenu des résultats similaires (ici les journaux enregistrés dans 3,5 FF):

Fri Dec 18 2009 17:53:58 GMT+0100 
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 

Le onreadystatechange ne sera jamais appelé. Dans ces navigateurs, seul l'écouteur onload est utile pour détecter la fin d'un chargement de script, le paramètre onreadystatechange n'est pas nécessaire.

1

Dans Internet Explorer, le gestionnaire onreadystatechange se déclenche comme prévu, après la fin du script.

je fis le same test dans Internet Explorer 6, Internet Explorer 7 et Internet Explorer 8, avec des résultats similaires dans ces trois navigateurs (ici les journaux enregistrés dans Internet Explorer 6):

Fri Dec 18 18:14:51 UTC+0100 2009 
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: complete 

Ici, avec test en utilisant un fichier local, le readyState est toujours "complet", et il était toujours le même après plusieurs rafraîchissement de la page. Toutefois, comme indiqué dans this post by Nicholas C. Zakas, vous pouvez également observer «chargé» et «terminé», ou simplement «chargé», dans des circonstances différentes.

1

J'ai trouvé qu'Internet Explorer (test en 9) n'a pas toujours votre script prêt quand readyState === 'chargé'. J'ai eu du succès en utilisant ce gestionnaire d'événements (en 9 bien sûr) onactivate. Je tirais mes cheveux avant.

0

Des résultats similaires dans le Chrome.

ne prend pas onReady ...

Juste onload et onerror.

Questions connexes