执行通过 DOM 插入加载的 javascript

发布于 2024-12-06 02:46:36 字数 3494 浏览 0 评论 0原文

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

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

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

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

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

因此,在我的代码文件“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);

但结果总是相同的,我从未看到消息“hello from test”。事实上,我什至可以在 load_test 函数中放置警报 - 如果我在“s.onload = s.readystatechange ..”行之前放置警报,我会看到该消息,但该 onload 函数中永远不会出现警报。因此,动态添加的脚本的 onload 似乎永远不会触发。

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

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

皮特


感谢大家的意见。

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

为了响应您的评论,新脚本将插入到页面的头部(使用 insertBefore 语句),就在原始脚本块之前(假设原始脚本块位于头部,事实确实如此)。

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

我的问题是,加载脚本后,它根本无法运行,但我认为我实际上遇到了一些缓存问题,因为我已经使用上面发布的第一个链接中描述的模式(这里又是针对好的措施: http://friendbit.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”是个好主意,即使在这种情况下脚本附加到窗口加载事件。

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

再次感谢您的帮助。

皮特

I'm working on something that will add a widget to a customer's site, and I want to load my js asynchronously so as not to block the customer's page loading. I've been reading a lot of threads about this, and have been trying to implement the pattern suggested here as my project is very similar:

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

The problem I have is the code in my dynamically-loaded javascript file just doesn't get executed. Sorry if this seems to be a duplicate question, but I've spent hours searching and trying slightly different techniques, and I've read numerous posts including these stackoverflow questions:

but I'm still struggling to make this work, so I was hoping if I ask the question directly someone here might be able to help me out!

I've currently got the following as a really basic test; obviously there's a lot more going on in my real script, but I just need to understand what's happening here (or, in fact, what's not happening).

So in my code file "test.js" I simply have:

run_test = function () {
    alert('hello from test');
};

then on the page I have:

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

I've already tried several variations on this - I've tried removing "s.async = true" just to see if it makes a difference, but it doesn't. I originally had the following instead of "load_test();", as suggested in the first post I mentioned:

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

but the result is always the same, I never see the message "hello from test". In fact I can even put alerts in the load_test function - if I put an alert just before the line "s.onload = s.readystatechange .." I see that message, but an alert within that onload function never appears. So it would appear that the dynamically added script's onload never fires.

BTW as an aside - may or may not be relevant, but I generally test in Firefox, and if I look at the html in firebug, I see the test.js script has been loaded, but if I expand that node I just see the message "Reload the page to get source for ...". Doesn't matter how many times I reload the page, I can't see the code. I have tried testing in other browsers with the same results.

Can't help feeling I'm missing something fundamental here; any help would be very much appreciated!

Pete


Thanks all for the input.

@zzzzBov, thanks for the example, although I'm not sure I completely understand still - I thought that "onload" would fire once after the script finishes loading, in the same way as attaching code to the onload event of the page. My understanding of "onreadystatechange" was that it was just to catch the same thing in IE.

In response to your comments, the new script is inserted in the head of the page (with the insertBefore statement) right before the original script block (assuming the original script block is in the head, which it is).

With regard to the test.js path, I omitted the path just to simplify the example. My path to the script is definitely correct; I can see via firebug that the script is actually added (to the head).

My problem was that after the script loaded, it simply failed to run, but I think I was actually hitting some caching problems as I've since got this working using the pattern described in the first link I posted above (here it is again for good measure: http://friendlybit.com/js/lazy-loading-asyncronous-javascript/).

So my code is something like this:

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

If you check the comments on that post, I think it's explained somewhere why it's a good idea to still include "s.async = true" even though in this case the script is attached to the window onload event.

My "real" main script does actually require jQuery, so I think my eventual solution will be to use something like this to load jQuery, then once I know that's loaded, let jQuery do the work of loading any other scripts I need.

Thanks again for the help.

Pete

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

反目相谮 2024-12-13 02:46:36

您的脚本存在一些问题。这是一个应该可行的方法。

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 的末尾,无论它在哪里。如果您想在页面其余部分之后加载脚本,请先等待页面其余部分加载(body.onloaddocument.onreadystatechange)调用loadScript

您的脚本的最大问题听起来像是 test.js 不存在于它被调用的路径中。确保内联添加 确实有效。

You've got a few issues with your script. Here's one that should work.

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

The issue with your load_test function is that it'll call run_test() before the new script has executed. Your script will remove the onload and onreadystatechange event callbacks at the first onreadystatechange event which is typically loading.

Also, async should be unnecessary, as the newly added script will be inserted at the end of the document.body wherever that may be. If you'd like to load the script after the rest of the page, then wait for the rest of the page to load (body.onload or document.onreadystatechange) before calling loadScript.

The biggest issue with your script sounds like test.js doesn't exist at the path it's being called. Make sure that adding <script type="text/javascript" src="test.js"></script> inline actually works.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文