执行通过DOM插入加载的javascript

Executing javascript loaded via DOM insertion

本文关键字:加载 javascript 插入 DOM 执行      更新时间:2023-09-26

我正在工作的东西,将添加一个小部件到客户的网站,我想异步加载我的js,以免阻止客户的页面加载。我已经阅读了很多关于这个的线程,并且一直在尝试实现这里建议的模式,因为我的项目非常相似:

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

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

  • 异步加载javascript,然后在执行回调之前检查DOM加载
  • 在js中加载jQuery,然后执行依赖于它的脚本
  • 动态加载脚本

但是我仍然在努力使这个工作,所以我希望如果我直接问这个问题,这里有人可能能够帮助我!

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

所以在我的代码文件"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();
})();

我已经尝试了几个变化-我已经尝试删除" .async = true"只是为了看看它是否有所不同,但它没有。我最初使用以下代码代替"load_test();",正如我在第一篇文章中提到的那样:

window.attachEvent ? window.attachEvent('onload', load_test) : window.addEventListener('load', load_test, false);

,但结果总是一样的,我从来没有看到消息"hello from test"。事实上,我甚至可以在load_test函数中添加警报——如果我在".onload = .readystatechange ."行之前添加警报的话。我看到了这条消息,但在onload函数内的警报从未出现。因此,动态添加的脚本的onload似乎永远不会触发。

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

忍不住觉得我在这里错过了一些基本的东西;任何帮助将非常感激!

皮特


感谢所有的输入。

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

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

关于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);
})();

如果你检查评论的那篇文章,我认为它解释了为什么这是一个好主意,仍然包括" .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()之前,新的脚本已经执行。您的脚本将在第一个onreadystatechange事件(通常是loading)中删除onloadonreadystatechange事件回调。

同样,async应该是不必要的,因为新添加的脚本将被插入到document.body的末尾,无论它在哪里。如果您希望在页面的其余部分之后加载脚本,那么在调用loadScript之前等待页面的其余部分加载(body.onloaddocument.onreadystatechange)。

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