编程语言
首页 > 编程语言> > 加载javascript异步,然后在执行回调之前检查加载的DOM

加载javascript异步,然后在执行回调之前检查加载的DOM

作者:互联网

问题:
异步加载js文件,然后在执行加载文件的回调之前检查是否加载了dom.

编辑:我们不使用jQuery;我们使用Prototype.
编辑:为代码示例添加了更多注释.

大家好,

我正在尝试异步加载我的所有js文件,以防止它们阻塞页面的其余部分.但是当脚本加载并调用回调时,我需要知道DOM是否已经加载,所以我知道如何构造回调.见下文:

//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);
    }
}

由于您可以从Google Talk:http://www.youtube.com/watch?v=52gL93S3usU&feature=related中了解到幕后的一些魔力,因此可以正确调用回调

询问DOM是否已经加载的最简单的跨浏览器方法是什么?

编辑
这是我使用的完整解决方案.
我使用普通方法包含了原型和异步脚本加载器.使用原型生活变得如此简单,所以我愿意阻止该脚本.

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

实际上,在我的代码中,我将上面的两个文件缩小并将它们放在一个文件中,以最大限度地减少传输时间和http请求.

然后我定义在DOM加载时我想要运行的内容,然后调用该函数来加载其他脚本.

<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>

同样,上面的请求实际上是使用minifier压缩成一个httpRequest.为了便于阅读,它们在这里分开.这篇文章的底部有一个片段,显示了minifier的代码.

asyncLoader.js的代码如下:

/**
 * 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 onl oad_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 
                  onl oad_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 
                  onl oad_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 
                  onl oad_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 = onl oad_queue.length;
    for (var i = 0; i < len; i++) {
        onl oad_queue[i]();
    }
    onl oad_queue = null;
});

如果您的脚本不依赖于完全加载的页面DOM,我添加了立即运行脚本的选项.

缩小的请求实际上看起来像:

<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>

他们使用的插件来自:http://code.google.com/p/minify/

谢谢您的帮助!!
-K

解决方法:

你需要的是一个简单的onload函数队列.另外请避免浏览器嗅探,因为它不稳定而且未来证明不足.有关完整源代码,请参阅[Demo]

var onl oad_queue = [];
var dom_loaded = false;

function loadScriptAsync(src, callback) {
  var script = document.createElement('script'); 
  script.type = "text/javascript";
  script.async = true;
  script.src = src;
  script.onload = script.onreadystatechange = function() {
    if (dom_loaded) 
      callback();
    else 
      onl oad_queue.push(callback);
    // clean up for IE and Opera
    script.onload = null;
    script.onreadystatechange = null;
  };
  var head = document.getElementsByTagName('head')[0];
  head.appendChild(script);
}

function domLoaded() {
   dom_loaded = true;
   var len = onl oad_queue.length;
   for (var i = 0; i < len; i++) {
     onl oad_queue[i]();
   }
   onl oad_queue = null;
};

// Dean's dom:loaded code goes here
// do stuff
domLoaded();

测试用法

loadScriptAsync(
  "http://code.jquery.com/jquery-1.4.4.js", 
  function() {
      alert("script has been loaded");
   }
);

标签:javascript,dom,asynchronous,callback,prototypejs
来源: https://codeday.me/bug/20190926/1818677.html