53 votes

Comment détecter si les fichiers javascript sont chargés ?

Existe-t-il un événement qui se déclenche lorsque des fichiers JavaScript sont chargés ? Le problème est apparu parce que YSlow recommande de déplacer les fichiers JavaScript en bas de la page. Cela signifie que $(document).ready(function1) est déclenché avant le fichier js qui contient le code de la fonction function1 est chargé.

Comment éviter ce genre de situation ?

76voto

T.J. Crowder Points 285826

Je n'ai pas de référence à portée de main, mais les balises script sont traitées dans l'ordre, et donc si vous mettez votre $(document).ready(function1) dans une balise script, après les balises script qui définissent function1, etc.

<script type='text/javascript' src='...'></script>
<script type='text/javascript' src='...'></script>
<script type='text/javascript'>
$(document).ready(function1);
</script>

Bien sûr, une autre approche serait de s'assurer que vous n'utilisez qu'une seule balise script, au total, en combinant les fichiers dans le cadre de votre processus de construction. (À moins que vous ne chargiez les autres depuis un CDN). Cela contribuera également à améliorer la vitesse perçue de votre page.

EDIT : Je viens de réaliser que je n'ai pas vraiment répondu à votre question : Je ne pense pas qu'il y ait un événement inter-navigateur qui soit déclenché, non. C'est possible si vous travaillez assez dur, voir ci-dessous. Vous pouvez tester les symboles et utiliser setTimeout pour replanifier :

<script type='text/javascript'>
function fireWhenReady() {
    if (typeof function1 != 'undefined') {
        function1();
    }
    else {
        setTimeout(fireWhenReady, 100);
    }
}
$(document).ready(fireWhenReady);
</script>

...mais vous ne devriez pas avoir à le faire si l'ordre de vos balises script est correct.


Mise à jour : Vous pouvez obtenir des notifications de chargement pour script des éléments que vous ajoutez à la page de manière dynamique si vous le souhaitez. Pour obtenir une large prise en charge par les navigateurs, vous devez faire deux choses différentes, mais en tant que technique combinée, cela fonctionne :

function loadScript(path, callback) {

    var done = false;
    var scr = document.createElement('script');

    scr.onload = handleLoad;
    scr.onreadystatechange = handleReadyStateChange;
    scr.onerror = handleError;
    scr.src = path;
    document.body.appendChild(scr);

    function handleLoad() {
        if (!done) {
            done = true;
            callback(path, "ok");
        }
    }

    function handleReadyStateChange() {
        var state;

        if (!done) {
            state = scr.readyState;
            if (state === "complete") {
                handleLoad();
            }
        }
    }
    function handleError() {
        if (!done) {
            done = true;
            callback(path, "error");
        }
    }
}

D'après mon expérience, la notification d'erreur ( onerror ) n'est pas fiable à 100 % sur tous les navigateurs. Notez également que certains navigateurs utilisent les deux mécanismes, d'où l'utilisation de l'option done pour éviter les notifications en double.

6voto

NickFitz Points 14977

Quand ils disent "Le bas de la page", ils ne veulent pas dire littéralement le bas : ils veulent dire juste avant la fermeture. </body> étiquette. Placez vos scripts à cet endroit et ils seront chargés avant l'événement DOMReady ; placez-les après et le DOM sera prêt avant qu'ils ne soient chargés (parce qu'il est complet lorsque la balise de fermeture </html> est analysée), ce qui, comme vous l'avez constaté, ne fonctionne pas.

Si vous vous demandez comment je sais que c'est ce qu'ils veulent dire : J'ai travaillé chez Yahoo ! et nous avons mis nos scripts juste avant le </body> tag :-)

EDIT : consultez également la réponse de T.J. Crowder et assurez-vous que vous avez les choses dans le bon ordre.

5voto

DalSoft Points 1827

Jetez un coup d'oeil à la fonction .load() de jQuery. http://api.jquery.com/load-event/

$('script').load(function () { });

3voto

Randhir Rawatlal Points 127

Suite à la réponse de @T.J. Crowder, j'ai ajouté une boucle externe récursive qui permet d'itérer à travers tous les scripts dans un tableau et ensuite d'exécuter une fonction une fois que tous les scripts sont chargés :

loadList([array of scripts], 0, function(){// do your post-scriptload stuff})

function loadList(list, i, callback)
{
    {
        loadScript(list[i], function()
        {
            if(i < list.length-1)
            {
                loadList(list, i+1, callback);  
            }
            else
            {
                callback();
            }
        })
    }
}

Bien sûr, vous pouvez créer une enveloppe pour vous débarrasser du "0" si vous le souhaitez :

function prettyLoadList(list, callback)
{
    loadList(list, 0, callback);
}

Bon travail @T.J. Crowder - J'ai eu peur de voir d'autres fils de discussion dire "ajoutez simplement un délai de quelques secondes avant de lancer le rappel".

2voto

Faiz Points 1660

Je fais toujours un appel à la fin des fichiers JavaScript pour enregistrer leur chargement et cela fonctionne parfaitement pour moi et pour tous les navigateurs.

Ex : J'ai un index.htm, Js1.js et Js2.js. J'ajoute la fonction IAmReady(Id) dans le header de index.htm et je l'appelle avec les paramètres 1 et 2 à la fin des fichiers, Js1 et Js2 respectivement. La fonction IAmReady aura une logique pour exécuter le code de démarrage une fois qu'elle reçoit deux appels (en stockant le nombre d'appels dans une variable statique/globale) des deux fichiers js.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X