草庐IT

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

coder 2024-05-16 原文

问题:
异步加载 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 演讲中了解:http://www.youtube.com/watch?v=52gL93S3usU&feature=related

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

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

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

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

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 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,我添加了立即运行脚本的选项。

缩小后的请求实际上是这样的:

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

最佳答案

您需要的是一个包含onload 函数的简单队列。也请避免浏览器嗅探,因为它不稳定且不是面向 future 的。有关完整的源代码,请参阅 [ 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 - 异步加载 javascript,然后在执行回调之前检查加载的 DOM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4249030/

有关javascript - 异步加载 javascript,然后在执行回调之前检查加载的 DOM的更多相关文章

  1. ruby-openid:执行发现时未设置@socket - 2

    我在使用omniauth/openid时遇到了一些麻烦。在尝试进行身份验证时,我在日志中发现了这一点:OpenID::FetchingError:Errorfetchinghttps://www.google.com/accounts/o8/.well-known/host-meta?hd=profiles.google.com%2Fmy_username:undefinedmethod`io'fornil:NilClass重要的是undefinedmethodio'fornil:NilClass来自openid/fetchers.rb,在下面的代码片段中:moduleNetclass

  2. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  3. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  4. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  5. ruby - 检查数组是否在增加 - 2

    这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife

  6. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  7. ruby - Chef 执行非顺序配方 - 2

    我遵循了教程http://gettingstartedwithchef.com/,第1章。我的运行list是"run_list":["recipe[apt]","recipe[phpap]"]我的phpapRecipe默认Recipeinclude_recipe"apache2"include_recipe"build-essential"include_recipe"openssl"include_recipe"mysql::client"include_recipe"mysql::server"include_recipe"php"include_recipe"php::modul

  8. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  9. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  10. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

随机推荐