Question Équivalent JavaScript pur de $ .ready () de jQuery - comment appeler une fonction quand la page / DOM est prête pour cela [dupliquer]


Cette question a déjà une réponse ici:

D'accord, cela pourrait être une question idiote, bien que je suis sûr qu'il y a beaucoup d'autres personnes qui posent la même question de temps en temps. Moi, je veux juste en être sûr à 100%. Avec jQuery, nous connaissons tous le merveilleux

$('document').ready(function(){});

Cependant, disons que je veux exécuter une fonction qui est écrite en JavaScript standard sans aucune bibliothèque, et que je veux lancer une fonction dès que la page est prête à la gérer. Quelle est la bonne façon d'aborder cela?

Je sais que je peux faire:

window.onload="myFunction()";

... ou je peux utiliser le body marque:

<body onload="myFunction()">

... ou je peux même essayer au bas de la page après tout, mais la fin body ou html tag comme:

<script type="text/javascript">
   myFunction();
</script>

Qu'est-ce qu'une méthode multi-navigateur (ancienne / nouvelle) -compliante d'émettre une ou plusieurs fonctions d'une manière comme jQuery $.ready()?


907
2018-03-27 23:57


origine


Réponses:


La chose la plus simple à faire en l'absence d'un cadre qui fait toute la compatibilité entre navigateurs est de simplement appeler votre code à la fin du corps. C'est plus rapide à exécuter qu'un onload gestionnaire car cela n'attend que le DOM pour être prêt, pas pour toutes les images à charger. Et, cela fonctionne dans tous les navigateurs.

<html>
<head>
</head>
<body>
Your HTML here

<script>
// self executing function here
(function() {
   // your page initialization code here
   // the DOM will be available here

})();
</script>
</body>
</html>

Si vous ne voulez vraiment pas le faire de cette façon et que vous avez besoin d'une compatibilité croisée avec le navigateur et que vous ne voulez pas attendre window.onload, alors vous devriez probablement aller voir comment un cadre comme jQuery implémente c'est $(document).ready() méthode. C'est assez impliqué en fonction des capacités du navigateur.

Pour vous donner une idée de ce que fait jQuery (qui fonctionnera partout où le tag de script est placé).

Si supporté, il essaye la norme:

document.addEventListener('DOMContentLoaded', fn, false);

avec un repli à:

window.addEventListener('load', fn, false )

ou pour les anciennes versions d'IE, il utilise:

document.attachEvent("onreadystatechange", fn);

avec un repli à:

window.attachEvent("onload", fn);

Et, il y a quelques trucs dans le chemin du code IE que je ne suis pas tout à fait, mais il semble que cela a quelque chose à voir avec les cadres.


Voici un substitut complet pour jQuery .ready() écrit en javascript simple:

(function(funcName, baseObj) {
    // The public function name defaults to window.docReady
    // but you can pass in your own object and own function name and those will be used
    // if you want to put them in a different namespace
    funcName = funcName || "docReady";
    baseObj = baseObj || window;
    var readyList = [];
    var readyFired = false;
    var readyEventHandlersInstalled = false;

    // call this when the document is ready
    // this function protects itself against being called more than once
    function ready() {
        if (!readyFired) {
            // this must be set to true before we start calling callbacks
            readyFired = true;
            for (var i = 0; i < readyList.length; i++) {
                // if a callback here happens to add new ready handlers,
                // the docReady() function will see that it already fired
                // and will schedule the callback to run right after
                // this event loop finishes so all handlers will still execute
                // in order and no new ones will be added to the readyList
                // while we are processing the list
                readyList[i].fn.call(window, readyList[i].ctx);
            }
            // allow any closures held by these functions to free
            readyList = [];
        }
    }

    function readyStateChange() {
        if ( document.readyState === "complete" ) {
            ready();
        }
    }

    // This is the one public interface
    // docReady(fn, context);
    // the context argument is optional - if present, it will be passed
    // as an argument to the callback
    baseObj[funcName] = function(callback, context) {
        if (typeof callback !== "function") {
            throw new TypeError("callback for docReady(fn) must be a function");
        }
        // if ready has already fired, then just schedule the callback
        // to fire asynchronously, but right away
        if (readyFired) {
            setTimeout(function() {callback(context);}, 1);
            return;
        } else {
            // add the function and context to the list
            readyList.push({fn: callback, ctx: context});
        }
        // if document already ready to go, schedule the ready function to run
        if (document.readyState === "complete") {
            setTimeout(ready, 1);
        } else if (!readyEventHandlersInstalled) {
            // otherwise if we don't have event handlers installed, install them
            if (document.addEventListener) {
                // first choice is DOMContentLoaded event
                document.addEventListener("DOMContentLoaded", ready, false);
                // backup is window load event
                window.addEventListener("load", ready, false);
            } else {
                // must be IE
                document.attachEvent("onreadystatechange", readyStateChange);
                window.attachEvent("onload", ready);
            }
            readyEventHandlersInstalled = true;
        }
    }
})("docReady", window);

La dernière version du code est partagée publiquement sur GitHub à https://github.com/jfriend00/docReady

Usage:

// pass a function reference
docReady(fn);

// use an anonymous function
docReady(function() {
    // code here
});

// pass a function reference and a context
// the context will be passed to the function as the first argument
docReady(fn, context);

// use an anonymous function with a context
docReady(function(context) {
    // code here that can use the context argument that was passed to docReady
}, ctx);

Cela a été testé dans:

IE6 and up
Firefox 3.6 and up
Chrome 14 and up
Safari 5.1 and up
Opera 11.6 and up
Multiple iOS devices
Multiple Android devices

Mise en œuvre de travail et banc d'essai: http://jsfiddle.net/jfriend00/YfD3C/


Voici un résumé de comment cela fonctionne:

  1. Créé un IIFE (expression de la fonction invoquée immédiatement) afin que nous puissions avoir des variables d'état non publiques.
  2. Déclarer une fonction publique docReady(fn, context)
  3. Quand docReady(fn, context) est appelée, vérifiez si le gestionnaire prêt a déjà été déclenché. Si c'est le cas, il suffit de planifier le rappel nouvellement ajouté à feu juste après que ce thread de JS se termine avec setTimeout(fn, 1).
  4. Si le gestionnaire prêt n'a pas déjà été déclenché, ajoutez ce nouveau rappel à la liste des rappels à appeler ultérieurement.
  5. Vérifiez si le document est déjà prêt. Si c'est le cas, exécutez tous les gestionnaires prêts.
  6. Si nous n'avons pas encore installé d'écouteurs d'événement pour savoir quand le document sera prêt, installez-les maintenant.
  7. Si document.addEventListener existe, puis installez les gestionnaires d'événements en utilisant .addEventListener() pour les deux "DOMContentLoaded" et "load" événements. La "charge" est un événement de sauvegarde pour la sécurité et ne devrait pas être nécessaire.
  8. Si document.addEventListener n'existe pas, puis installez les gestionnaires d'événements à l'aide de .attachEvent() pour "onreadystatechange" et "onload" événements.
  9. dans le onreadystatechange événement, vérifiez pour voir si document.readyState === "complete" et si c'est le cas, appelez une fonction pour tirer tous les gestionnaires prêts.
  10. Dans tous les autres gestionnaires d'événements, appelez une fonction pour déclencher tous les gestionnaires prêts.
  11. Dans la fonction pour appeler tous les gestionnaires prêts, vérifiez une variable d'état pour voir si nous avons déjà tiré. Si nous avons, ne faites rien. Si nous n'avons pas encore été appelé, parcourez le tableau des fonctions prêtes et appelez chacune dans l'ordre où elles ont été ajoutées. Définissez un drapeau pour indiquer que tous ont été appelés afin qu'ils ne soient jamais exécutés plus d'une fois.
  12. Effacez le tableau de fonctions afin que toutes les fermetures qu'ils pourraient utiliser puissent être libérées.

Handlers enregistrés avec docReady() sont garantis d'être tirés dans l'ordre où ils ont été enregistrés.

Si vous appelez docReady(fn) une fois que le document est déjà prêt, le rappel sera planifié pour s'exécuter dès que le thread d'exécution en cours setTimeout(fn, 1). Cela permet au code appelant de toujours supposer qu'il s'agit de rappels asynchrones qui seront appelés plus tard, même si plus tard, il se termine dès que le thread courant de JS est terminé et qu'il conserve l'ordre d'appel.


1350
2018-03-28 00:46



Je voudrais mentionner quelques-unes des façons possibles ici avec un astuce javascript pur qui fonctionne sur tous les navigateurs:

// with jQuery 
$(document).ready(function(){ /* ... */ });

// shorter jQuery version 
$(function(){ /* ... */ });

// without jQuery (doesn't work in older IEs)
document.addEventListener('DOMContentLoaded', function(){ 
    // your code goes here
}, false);

// and here's the trick (works everywhere)
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
// use like
r(function(){
    alert('DOM Ready!');
});

L'astuce ici, comme expliqué par le auteur original, est-ce que nous vérifions la document.readyState propriété. S'il contient la chaîne in (un péché uninitialized et loading, les deux premiers États prêts DOM sur 5) nous définissons un délai et vérifions à nouveau. Sinon, nous exécutons la fonction passée.

Et voici la jsFiddle pour le tour qui fonctionne sur tous les navigateurs. 

Grâce à Tutorialzine pour l'inclure dans leur livre.


99
2018-05-19 07:58



Si vous faites VANILLE plaine JavaScript sans jQuery, vous devez utiliser (Internet Explorer 9 ou plus récent):

document.addEventListener("DOMContentLoaded", function(event) {
    // Your code to run since DOM is loaded and ready
});

Ci-dessus est l'équivalent de jQuery .ready:

$(document).ready(function() {
    console.log("Ready!");
});

Ce qui pourrait aussi être écrit SHORTHAND comme ça, qui jQuery fonctionnera après le prêt même se produit.

$(function() {
    console.log("ready!");
});

A ne pas confondre avec ci-dessous (qui n'est pas destiné à être DOM prêt):

N'utilisez PAS un IIFE comme ceci qui est auto-exécutable:

 Example:

(function() {
   // Your page initialization code here  - WRONG
   // The DOM will be available here   - WRONG
})();

Cet IIFE n'attendra pas le chargement de votre DOM. (Je parle même de la dernière version du navigateur Chrome!)


81
2017-07-01 20:31



Testé dans IE9, et le dernier Firefox et Chrome et également pris en charge dans IE8.

document.onreadystatechange = function () {
  var state = document.readyState;
  if (state == 'interactive') {
      init();
  } else if (state == 'complete') {
      initOnCompleteLoad();
  }
}​;

Exemple: http://jsfiddle.net/electricvisions/Jacck/

UPDATE - version réutilisable

Je viens de développer ce qui suit. C'est un équivalent plutôt simpliste de jQuery ou Dom prêt sans compatibilité ascendante. Il a probablement besoin de plus de raffinement. Testé dans les dernières versions de Chrome, Firefox et IE (10/11) et devrait fonctionner dans les anciens navigateurs comme commenté. Je mettrai à jour si je trouve des problèmes.

window.readyHandlers = [];
window.ready = function ready(handler) {
  window.readyHandlers.push(handler);
  handleState();
};

window.handleState = function handleState () {
  if (['interactive', 'complete'].indexOf(document.readyState) > -1) {
    while(window.readyHandlers.length > 0) {
      (window.readyHandlers.shift())();
    }
  }
};

document.onreadystatechange = window.handleState;

Usage:

ready(function () {
  // your code here
});

Il est écrit pour gérer le chargement asynchrone de JS mais vous voudrez peut-être synchroniser le chargement de ce script à moins que vous ne minimisiez. Je l'ai trouvé utile dans le développement.

Les navigateurs modernes prennent également en charge le chargement asynchrone de scripts, ce qui améliore encore l'expérience. La prise en charge d'async signifie que plusieurs scripts peuvent être téléchargés simultanément tout en restituant la page. Faites attention quand vous dépendez d'autres scripts chargés de manière asynchrone ou utilisez un minifier ou quelque chose comme browserify pour gérer les dépendances.


71
2018-06-10 13:27



Les bonnes personnes à HubSpot ont une ressource où vous pouvez trouver des méthodologies Javascript pur pour réaliser beaucoup de bonté jQuery - y compris ready

http://youmightnotneedjquery.com/#ready

function ready(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else if (document.addEventListener) {
    document.addEventListener('DOMContentLoaded', fn);
  } else {
    document.attachEvent('onreadystatechange', function() {
      if (document.readyState != 'loading')
        fn();
    });
  }
}

exemple d'utilisation en ligne:

ready(function() { alert('hello'); });

17
2018-03-28 00:46



Votre méthode (placer le script avant la balise body de fermeture)

<script>
   myFunction()
</script>
</body>
</html>

est un moyen fiable de prendre en charge les anciens et les nouveaux navigateurs.


7
2017-11-24 05:15



Prêt

function ready(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();}

Utilisez comme

ready(function(){
    //some code
});

Pour le code auto-invoquant

(function(fn){var d=document;(d.readyState=='loading')?d.addEventListener('DOMContentLoaded',fn):fn();})(function(){

    //Some Code here
    //DOM is avaliable
    //var h1s = document.querySelector("h1");

});

Support: IE9 +


4
2018-06-19 06:03



Je ne suis pas sûr de ce que vous demandez, mais peut-être que cela peut aider:

window.onload = function(){
    // Code. . .

}

Ou:

window.onload = main;

function main(){
    // Code. . .

}

3
2018-03-28 00:04