web-dev-qa-db-fra.com

Possible de différer le chargement de jQuery?

Avouons-le, jQuery/jQuery-ui est un téléchargement lourd.

Google recommande chargement différé de JavaScript pour accélérer le rendu initial. Ma page utilise jQuery pour configurer certains onglets qui sont placés bas sur la page (principalement hors de la vue initiale) et je voudrais reporter jQuery jusqu'à ce que la page soit restituée.

Le code de report de Google ajoute une balise au DOM après le chargement de la page en se connectant à l'événement body onLoad:

<script type="text/javascript">

 // Add a script element as a child of the body
 function downloadJSAtOnload() {
 var element = document.createElement("script");
 element.src = "deferredfunctions.js";
 document.body.appendChild(element);
 }

 // Check for browser support of event handling capability
 if (window.addEventListener)
 window.addEventListener("load", downloadJSAtOnload, false);
 else if (window.attachEvent)
 window.attachEvent("onload", downloadJSAtOnload);
 else window.onload = downloadJSAtOnload;

</script>

Je voudrais différer le chargement de jQuery de cette façon, mais quand je l'ai essayé, mon code jQuery n'a pas trouvé jQuery (pas complètement inattendu de ma part):

$(document).ready(function() {
    $("#tabs").tabs();
});

Il semble donc que je doive trouver un moyen de différer l'exécution de mon code jQuery jusqu'à ce que jQuery soit chargé. Comment puis-je détecter que la balise ajoutée a terminé le chargement et l'analyse?

En corollaire, il apparaît que chargement asynchrone peut également contenir une réponse.

Des pensées?

65
Kevin P. Rice

Essayez ceci, quelque chose que j'ai édité il y a quelque temps à partir du bookmarklet jQuerify. Je l'utilise fréquemment pour charger jQuery et exécuter des trucs après son chargement. Vous pouvez bien sûr y remplacer l'URL par votre propre URL à votre requête personnalisée.

(function() {
      function getScript(url,success){
        var script=document.createElement('script');
        script.src=url;
        var head=document.getElementsByTagName('head')[0],
            done=false;
        script.onload=script.onreadystatechange = function(){
          if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) {
            done=true;
            success();
            script.onload = script.onreadystatechange = null;
            head.removeChild(script);
          }
        };
        head.appendChild(script);
      }
        getScript('http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js',function(){
            // YOUR CODE GOES HERE AND IS EXECUTED AFTER JQUERY LOADS
        });
    })();

Je voudrais vraiment combiner jQuery et jQuery-UI en un seul fichier et utiliser une URL. Si vous voulez vraiment les charger séparément, enchaînez simplement les getScripts:

getScript('http://myurltojquery.js',function(){
        getScript('http://myurltojqueryUI.js',function(){
              //your tab code here
        })
});
51
ampersand

Comme il s'agit d'une question de premier ordre sur un sujet important, permettez-moi d'être si audacieux pour donner ma propre opinion à ce sujet sur la base d'une réponse précédente de @valmarv et @amparsand.

J'utilise un tableau multidimensionnel pour charger les scripts. Regrouper ceux qui n'ont pas de dépendances entre eux:

var dfLoadStatus = 0;
var dfLoadFiles = [
      ["http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"],
      ["http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js",
       "/js/somespecial.js",
       "/js/feedback-widget.js#2312195",
       "/js/nohover.js"]
     ];

function downloadJSAtOnload() {
    if (!dfLoadFiles.length) return;

    var dfGroup = dfLoadFiles.shift();
    dfLoadStatus = 0;

    for(var i = 0; i<dfGroup.length; i++) {
        dfLoadStatus++;
        var element = document.createElement('script');
        element.src = dfGroup[i];
        element.onload = element.onreadystatechange = function() {
        if ( ! this.readyState || 
               this.readyState == 'complete') {
            dfLoadStatus--;
            if (dfLoadStatus==0) downloadJSAtOnload();
        }
    };
    document.body.appendChild(element);
  }

}

if (window.addEventListener)
    window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
    window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;

Il charge d'abord jquery après son chargement, il continue à charger les autres scripts à la fois. Vous pouvez facilement ajouter des scripts en ajoutant au tableau n'importe où sur votre page:

dfLoadFiles.Push(["/js/loadbeforeA.js"]);
dfLoadFiles.Push(["/js/javascriptA.js", "/js/javascriptB.js"]);
dfLoadFiles.Push(["/js/loadafterB.js"]);
13
Pevawi

Voici une bonne description de approche moderne pour le chargement javascript asynchrone/différé . Mais cela ne fonctionne pas pour les scripts en ligne

<script type="text/javascript" src="/jquery/3.1.1-1/jquery.min.js" defer></script>
<script type="text/javascript" defer>
    $(function () {   //  <- jquery is not yet initialized
      ...
    });
</script>

@Nilskp - externalize script a proposé la solution la plus simple pour le chargement asynchrone:

<script type="text/javascript" src="/jquery/3.1.1-1/jquery.min.js" defer></script>
<script type="text/javascript" src="resources/js/onload.js" defer></script>
8
GKislin
element.addEventListener("load", function () {
    $('#tabs').tabs()
}, false);

Essayez ça.

3
McKayla

Mettez jQuery et votre code dépendant de jQuery à la fin de votre fichier HTML.

Edit: Un peu plus clair

<html>
<head></head>
<body>
    <!-- Your normal content here -->
    <script type="text/javascript" src="http://path/to/jquery/jquery.min.js"></script>
    <script>//Put your jQuery code here</script>
</body>
</html>
3
Dan

J'ajoute ce morceau de code après la balise de script jquery async/defered, cela définit une fonction temporaire $ qui accumulera tout ce qui doit être exécuté lorsque tout est terminé de charger, puis une fois que nous aurons fini d'utiliser $ that à ce moment-là serait écrasé pour exécuter les fonctions. Avec ce morceau de code, il n'est pas nécessaire de modifier la syntaxe de chargement de jQuery plus bas dans le document.

<script defer async src="https://code.jquery.com/jquery-2.2.0.min.js">
<script>
    var executeLater = [];
    function $(func) {
        executeLater.Push(func);
    }
    window.addEventListener('load', function () {
        $(function () {
            for (var c = 0; c < executeLater.length; c++) {
                executeLater[c]();
            }
        });
    })
</script>

....et alors...

<script>
    $(function() {
        alert("loaded");
    });
</script>
2
asiop

Dans certaines situations, vous pouvez déclencher un événement lorsque jquery est chargé.

<script type="text/javascript">
    (function (window) {

        window.jQueryHasLoaded = false;

        document.body.addEventListener('jqueryloaded', function (e) {
            console.log('jqueryloaded ' + new Date() );
        }, false);

        function appendScript(script) {
            var tagS = document.createElement("script"), 
                s = document.getElementsByTagName("script")[0];
            tagS.src = script.src;
            s.parentNode.insertBefore(tagS, s);

            if ( script.id == 'jquery' ) {
                tagS.addEventListener('load', function (e) {
                    window.jQueryHasLoaded = true;
                    var jQueryLoaded = new Event('jqueryloaded');
                    document.body.dispatchEvent(jQueryLoaded);
                }, false);
            }
        }

        var scripts = [
            {
                'id': 'jquery',
                'src': 'js/libs/jquery/jquery-2.0.3.min.js'
            },
            {
                'src': 'js/myscript1.js'
            },
            {
                'src': 'js/myscript2.js'
            }
        ];

        for (var i=0; i < scripts.length; i++) {
            appendScript(scripts[i]);
        }

    }(window));
</script>

Enveloppez ensuite vos dépendances dans une fonction:

// myscript1.js 
(function(){ 

    function initMyjQueryDependency() {
        console.log('my code is executed after jquery is loaded!');
        // here my code that depends on jquery
    }

    if ( jQueryHasLoaded === true )
        initMyjQueryDependency();
    else
        document.body.addEventListener('jqueryloaded', initMyjQueryDependency, false);

}());

Si jquery finit de se charger après les autres scripts, vos dépendances seront exécutées lorsque l'événement jqueryloaded est déclenché.

Si jquery est déjà chargé, jQueryHasLoaded === true, Votre dépendance sera exécutée initMyjQueryDependency().

2
mex23
<!doctype html>
<html>
    <head>

    </head>
    <body>
        <p>If you click on the "Hide" button, I will disappear.</p>
        <button id="hide" >Hide</button>
        <button id="show" >Show</button>

        <script type="text/javascript">
            function loadScript(url, callback) {

                var script = document.createElement("script")
                script.type = "text/javascript";

                if (script.readyState) {  //IE
                    script.onreadystatechange = function() {
                        if (script.readyState == "loaded" ||
                                script.readyState == "complete") {
                            script.onreadystatechange = null;
                            callback();
                        }
                    };
                } else {  //Others
                    script.onload = function() {
                        callback();
                    };
                }

                script.src = url;
                document.body.appendChild(script);
            }
            loadScript("http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js",
                    function() {
                        //YAHOO.namespace("mystuff");
                        $("#show").click(function() {
                            $("p").show();
                        });
                        $("#hide").click(function() {
                            $("p").hide();
                        });

                        //more...
                    });
        </script>

    </body>
</html>
1
Nanhe Kumar

Eh bien, il me semble, tout ce que vous avez à faire est soit a) d'ajouter le code jQuery que vous souhaitez exécuter à la charge, à la fin du fichier jQuery ou b) de l'ajouter à la fonction downloadJSAtOnload comme ceci:

<script type="text/javascript">

 // Add a script element as a child of the body
 function downloadJSAtOnload() {
 var element = document.createElement("script");
 element.src = "deferredfunctions.js";
 document.body.appendChild(element);
 $("#tabs").tabs(); // <==== NOTE THIS. This should theoretically run after the
                    // script has been appended, though you'll have to test this
                    // because I don't know if the JavaScript above will wait for
                    // the script to load before continuing
 }

 // Check for browser support of event handling capability
 if (window.addEventListener)
 window.addEventListener("load", downloadJSAtOnload, false);
 else if (window.attachEvent)
 window.attachEvent("onload", downloadJSAtOnload);
 else window.onload = downloadJSAtOnload;

</script>

Voici ma version qui prend en charge le chaînage pour être sûr que les scripts sont chargés les uns après les autres, en fonction du code de esperluette:

var deferredJSFiles = ['jquery/jquery', 'file1', 'file2', 'file3'];
function downloadJSAtOnload() {
    if (!deferredJSFiles.length)
        return;
    var deferredJSFile = deferredJSFiles.shift();
    var element = document.createElement('script');
    element.src = deferredJSFile.indexOf('http') == 0 ? deferredJSFile : '/js/' + deferredJSFile + '.js';
    element.onload = element.onreadystatechange = function() {
        if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')
            downloadJSAtOnload();
    };
    document.body.appendChild(element);
}
if (window.addEventListener)
    window.addEventListener('load', downloadJSAtOnload, false);
else if (window.attachEvent)
    window.attachEvent('onload', downloadJSAtOnload);
else
    window.onload = downloadJSAtOnload;
1
valmarv

Je pense que Modernizr.load () mérite une mention ici - il gère très bien le chargement des dépendances

1
Mike

Le code suivant devrait charger vos scripts une fois le chargement de la fenêtre terminé:

<html>
<head>
    <script>
    var jQueryLoaded = false;
    function test() {
        var myScript = document.createElement('script');
        myScript.type = 'text/javascript';
        myScript.async = true;
        myScript.src = jQueryLoaded ? 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.js' : 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js';
        document.body.appendChild(myScript);

        if(!jQueryLoaded){
            alert('jquery was loaded');
            jQueryLoaded = true;
            test();
        } else {
            alert('jqueryui was loaded');   
        }
    }

    if (window.addEventListener){
        alert('window.addEventListener');
        window.addEventListener("load", test, false);
    } else if (window.attachEvent){
        alert('window.attachEvent');
        window.attachEvent("onload", test);
    } else{
        alert('window.onload');
        window.onload = test;
    }
    </script>
</head>
<body>
<p>Placeholder text goes here</p>
</body>
</html>

A fonctionné pour moi dans Chrome, FF et IE9 - faites-moi savoir si cela aide

1
Jeremy Battle

Jetez un œil jQuery.holdReady()

"Retient ou libère l'exécution de l'événement prêt de jQuery." (jQuery 1.6+)

http://api.jquery.com/jQuery.holdReady/

0
mikeycgto

Semble que vous avez juste besoin de <script defer>: http://www.w3schools.com/tags/att_script_defer.asp

0
c-smile