Charge javascript asynchrone, puis vérifier DOM chargé avant l'exécution de rappel

Problème:

Charger des fichiers js de manière asynchrone, puis vérifiez si le dom est chargé avant le rappel de chargement des fichiers est exécuté.

edit: Nous n'utilisons pas de jQuery, Prototype.

edit: ajouté plus de commentaires pour l'exemple de code.

Hé les gars,

Je suis en train de charger tous mes fichiers js asynchrone afin de les empêcher de bloquer le reste de la page. Mais quand les scripts de la charge et de la fonction de rappel est appelée, j'ai besoin de savoir si le DOM est chargé ou pas, donc je sais comment la structure de la fonction de rappel. Voir ci-dessous:

//load asynchronously
(function(){
        var e = document.createElement('script'); 
        e.type = "text/javascript";
        e.async = true;
        e.src = srcstr; 
        //a little magic to make the callback happen
        if(navigator.userAgent.indexOf("Opera")){
            e.text = "initPage();";
        }else if(navigator.userAgent.indexOf("MSIE")){
            e.onreadystatechange = initPage;
        }else{
            e.innerHTML = "initPage();";
        }
        //attach the file to the document
        document.getElementsByTagName('head')[0].appendChild(e);
})();

initPageHelper = function(){ 
    //requires DOM be loaded
}

initPage = function(){
    if(domLoaded){ //if dom is already loaded, just call the function
        initPageHelper();
    }else{ //if dom is not loaded, attach the function to be run when it does load
        document.observe("dom:loaded", initPageHelper);
    }
}

La fonction de rappel est appelée correctement à cause de la magie derrière les scènes que vous pouvez apprendre à partir de ce Google talk: http://www.youtube.com/watch?v=52gL93S3usU&feature=related

Ce qui est le plus facile, la croix-navigateur méthode pour demander si le DOM est chargé déjà?

MODIFIER

Voici la solution complète, je suis allé avec.

J'ai inclus prototype et de l'asynchrone chargeur de script à l'aide de la méthode normale. La vie est tellement plus facile de prototype, donc, je suis prêt à bloc pour ce script.

<script type="text/javascript" src="prototype/prototype.js"></script>
<script type="text/javascript" src="asyncLoader.js"></script>

Et en fait, dans mon code, j'ai minimisé les deux fichiers ci-dessus et les mettre ensemble dans un seul fichier afin de réduire les temps de transfert et les requêtes http.

Puis-je définir ce que je veux exécuter lorsque le DOM, et ensuite appeler la fonction pour charger les autres scripts.

<script type="text/javascript">
    initPage = function(){
    ...
    }
</script>
<script type="text/javascript">
    loadScriptAsync("scriptaculous/scriptaculous.js", initPage);
    loadScriptAsync("scriptaculous/effects.js", initPage);
    loadScriptAsync("scriptaculous/controls.js", initPage);
        ...
    loadScriptAsync("mypage.js", initPage);
</script>

De même, les demandes ci-dessus sont en fait compressés en un seul httpRequest à l'aide d'un minifier. Ils sont laissés séparé ici pour des raisons de lisibilité. Il y a un extrait en bas de ce post montrant à quoi ressemble le code avec le minifier.

Le code pour asyncLoader.js est la suivante:

/**
* Allows you to load js files asynchronously, with a callback that can be 
* called immediately after the script loads, OR after the script loads and 
* after the DOM is loaded. 
* 
* Prototype.js must be loaded first. 
* 
* For best results, create a regular script tag that calls a minified, combined
* file that contains Prototype.js, and this file. Then all subsequent scripts
* should be loaded using this function. 
* 
*/
var onload_queue = [];
var dom_loaded = false;
function loadScriptAsync(src, callback, run_immediately) {
var script = document.createElement('script'); 
script.type = "text/javascript";
script.async = true;
script.src = src;
if("undefined" != typeof callback){
script.onload = function() {
if (dom_loaded || run_immediately) 
callback();
else 
onload_queue.push(callback);
//clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
};
script.onreadystatechange = function() {
if (script.readyState == 'complete'){
if (dom_loaded || run_immediately) 
callback();
else 
onload_queue.push(callback);
//clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
}else if(script.readyState == 'loaded'){
eval(script);
if (dom_loaded || run_immediately) 
callback();
else 
onload_queue.push(callback);
//clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
}
};
}
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);
}
document.observe("dom:loaded", function(){
dom_loaded = true;
var len = onload_queue.length;
for (var i = 0; i < len; i++) {
onload_queue[i]();
}
onload_queue = null;
});

J'ai ajouté la possibilité d'exécuter un script immédiatement, si vous avez des scripts qui ne reposent pas sur la page de DOM d'être complètement chargé.

La minimisé les demandes effectivement ressembler:

<script type="text/javascript" src="/min/?b=javascript/lib&f=prototype/prototype.js,asyncLoader.js"></script>
<script type="text/javascript"> initPage = function(e){...}</script>
<script type="text/javascript">
srcstr = "/min/?f=<?=implode(',', $js_files)?>";
loadScriptAsync(srcstr, initPage);
</script>

Ils sont en utilisant le plugin à partir de: http://code.google.com/p/minify/

Merci pour l'aide!!

-K

J'utilise jQuery $(document).prêt() de l'événement. La plus simple, la croix-navigateur de la manière que je sais.
Vous pouvez utiliser un drapeau que vous pouvez définir quand le DOM est chargé et vérifier que l'indicateur dans votre rappel fn.
vous pouvez marquer une réponse comme acceptée si votre problème a été résolu.
désolé @galambalazs, j'ai marqué maintenant.

OriginalL'auteur Ken | 2010-11-22