加载javascript异步,然后在执行回调之前检查加载的DOM [英] Load javascript async, then check DOM loaded before executing callback

查看:29
本文介绍了加载javascript异步,然后在执行回调之前检查加载的DOM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Problem:
Load js files asynchronously, then check to see if the dom is loaded before the callback from loading the files is executed.

我们不使用jQuery;我们使用原型.
向代码示例添加了更多注释.

edit: We do not use jQuery; we use Prototype.
edit: added more comments to the code example.

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

I am trying to load all of my js files asynchronously so as to keep them from blocking the rest of the page. But when the scripts load and the callback is called, I need to know if the DOM has been loaded or not, so I know how to structure the callback. See below:

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

由于幕后的一些魔法,你可以从这个谷歌演讲中了解到回调被正确调用:http://www.youtube.com/watch?v=52gL93S3usU&feature=related

The callback gets called properly due to some magic behind the scenes that you can learn about from this Google talk: http://www.youtube.com/watch?v=52gL93S3usU&feature=related

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

What's the easiest, cross-browser method for asking if the DOM has loaded already?

编辑
这是我采用的完整解决方案.
我使用普通方法包含原型和异步脚本加载器.有了原型,生活就轻松多了,所以我愿意为那个脚本而阻止.

EDIT
Here's the full solution I went with.
I included prototype and the asynchronous script loader using the normal method. Life is just so much easier with prototype, so I'm willing to block for that script.

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

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

And actually, in my code I minified the two files above and put them together into one file to minimize transfer time and http requests.

然后我定义了我想在DOM加载时运行什么,然后调用函数加载其他脚本.

Then I define what I want to run when the DOM loads, and then call the function to load the other 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>

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

Likewise, the requests above are actually compressed into one httpRequest using a minifier. They are left separate here for readability. There is a snippet at the bottom of this post showing what the code looks like with the minifier.

asyncLoader.js 的代码如下:

The code for asyncLoader.js is the following:

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

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

I added the option to run a script immediately, if you have scripts that don't rely on the page DOM being fully loaded.

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

The minified requests actually look like:

<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/][1]

They are using the plugin from: [http://code.google.com/p/minify/][1]

推荐答案

您需要的是一个简单的 onload 函数队列.还请避免浏览器嗅探,因为它不稳定且不能保证未来的安全.有关完整源代码,请参阅[演示]

What you need is a simple queue of onload functions. Also please avoid browser sniffing as it is unstable and not future proof. For full source code see the [Demo]

var onload_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 
      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);
}

function domLoaded() {
   dom_loaded = true;
   var len = onload_queue.length;
   for (var i = 0; i < len; i++) {
     onload_queue[i]();
   }
   onload_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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆