jjzjj

javascript - 执行通过 DOM 插入加载的 javascript

coder 2025-01-03 原文

我正在研究将小部件添加到客户站点的东西,并且我想异步加载我的 js,以免阻止客户的页面加载。我一直在阅读很多关于此的主题,并且一直在尝试实现此处建议的模式,因为我的项目非常相似:

http://friendlybit.com/js/lazy-loading-asyncronous-javascript

我遇到的问题是我动态加载的 javascript 文件中的代码没有被执行。抱歉,如果这似乎是一个重复的问题,但我已经花了几个小时搜索和尝试略有不同的技术,并且我已经阅读了许多帖子,包括这些 stackoverflow 问题:

  • Load javascript async, then check DOM loaded before executing callback
  • Load jQuery in a js, then execute a script that depends on it
  • Loading scripts dynamically

  • 但我仍在努力完成这项工作,所以我希望如果我直接问这个问题,这里的人可能会帮助我!

    我目前有以下作为一个非常基本的测试;显然,在我的真实脚本中还有很多事情要做,但我只需要了解这里发生了什么(或者,事实上,没有发生什么)。

    所以在我的代码文件“test.js”中,我只有:
    run_test = function () {
        alert('hello from test');
    };
    

    然后在我的页面上:
    (function () {
         load_test = function () {
            var t = document.getElementsByTagName('script')[0];
            var s = document.createElement('script');
            s.type = 'text/javscript';
            s.async = true;
            s.src = 'test.js';
    
            s.onload = s.readystatechange = function () {
                if (run_test) run_test();
    
                s.onload = null;
                s.onreadystatechange = null;
            };
    
            t.parentNode.insertBefore(s, t);
        };
    
        load_test();
    })();
    

    我已经尝试了几种变体 - 我尝试删除“s.async = true”只是为了看看它是否有所作为,但它没有。正如我提到的第一篇文章中所建议的那样,我最初使用的是以下内容而不是“load_test();”:
    window.attachEvent ? window.attachEvent('onload', load_test) : window.addEventListener('load', load_test, false);
    

    但结果总是一样的,我从来没有看到“来自测试的你好”的消息。事实上,我什至可以在 load_test 函数中放置警报 - 如果我在“s.onload = s.readystatechange ..”行之前放置警报,我会看到该消息,但该 onload 函数中的警报永远不会出现。因此,动态添加的脚本的 onload 似乎永远不会触发。

    顺便说一句 - 可能相关也可能不相关,但我通常在 Firefox 中进行测试,如果我查看 firebug 中的 html,我会看到 test.js 脚本已加载,但如果我展开该节点,我只会看到消息“重新加载页面以获取...的源代码”。不管我重新加载页面多少次,我都看不到代码。我曾尝试在其他浏览器中进行测试,结果相同。

    不禁觉得我在这里缺少一些基本的东西;任何帮助将不胜感激!

    皮特

    感谢大家的投入。

    @zzzzBov,谢谢你的例子,虽然我不确定我是否完全理解 - 我认为“onload”会在脚本完成加载后触发一次,就像将代码附加到页面的 onload 事件一样。我对“onreadystatechange”的理解是,它只是为了在 IE 中捕获同样的东西。

    作为对您的评论的回应,新脚本被插入到页面头部(使用 insertBefore 语句),就在原始脚本 block 之前(假设原始脚本 block 在头部,它就是这样)。

    关于 test.js 路径,我省略了路径只是为了简化示例。我的脚本路径绝对正确;我可以通过 Firebug 看到该脚本实际上已添加(到头部)。

    我的问题是,在加载脚本后,它根本无法运行,但我认为我实际上遇到了一些缓存问题,因为我已经使用我上面发布的第一个链接中描述的模式进行了这项工作(这里又是好措施:http://friendlybit.com/js/lazy-loading-asyncronous-javascript/)。

    所以我的代码是这样的:
    (function () {
        var addscript = function () {
            var h = document.getElementsByTagName('head')[0],
                s = document.createElement('script');
            s.type = "text/javascript";
            s.async = true;
            s.src = "myscript.js";
            h.appendChild(s);
        };
        window.attachEvent ? window.attachEvent('onload', addscript) : 
            window.addEventListener('load', addscript, false);
    })();
    

    如果您查看该帖子的评论,我认为它在某处解释了为什么仍然包含“s.async = true”是一个好主意,即使在这种情况下脚本附加到窗口 onload 事件。

    我的“真正的”主脚本确实需要 jQuery,所以我认为我最终的解决方案是使用类似这样的东西来加载 jQuery,然后一旦我知道它已经加载,让 jQuery 来完成加载我需要的任何其他脚本的工作。

    再次感谢您的帮助。

    皮特

    最佳答案

    你的脚本有一些问题。这是一个应该工作的。

    function loadScript(src, callback)
    {
      var s, r;
      r = false;
      s = document.createElement('script');
      s.type = 'text/javascript';
      s.src = src;
      s.onload = s.onreadystatechange = function() {
        //console.log( this.readyState ); //uncomment this line to see which ready states are called.
        if ( !r && (!this.readyState || this.readyState == 'complete') )
        {
          r = true;
          callback();
        }
      };
      document.body.appendChild(s);
    }
    

    您的 load_test 的问题功能是它会调用run_test()在新脚本执行之前。您的脚本将删除 onloadonreadystatechange第一个 onreadystatechange 的事件回调通常为 loading 的事件.

    另外,async应该是不必要的,因为新添加的脚本将被插入到 document.body 的末尾。无论在哪里。如果您想在页面的其余部分之后加载脚本,则在调用 body.onload 之前等待页面的其余部分加载( document.onreadystatechangeloadScript ) .

    您的脚本最大的问题听起来像 test.js在它被调用的路径中不存在。确保添加 <script type="text/javascript" src="test.js"></script>内联实际上有效。

    关于javascript - 执行通过 DOM 插入加载的 javascript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7540715/

    有关javascript - 执行通过 DOM 插入加载的 javascript的更多相关文章

    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 - 通过 rvm 升级 ruby​​gems 的问题 - 2

      尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

    3. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

      我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

    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 - 通过 ruby​​ 进程共享变量 - 2

      我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

    6. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

      我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

    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-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

      我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

    9. 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("

    10. ruby - 为什么 Ruby 的 each 迭代器先执行? - 2

      我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试

    随机推荐