动态加载 JavaScript 文件

2022-08-30 01:38:02

如何可靠、动态地加载 JavaScript 文件?这将可用于实现一个模块或组件,当“初始化”组件时,组件将根据需要动态加载所有需要的JavaScript库脚本。

使用该组件的客户端不需要加载实现此组件的所有库脚本文件(并手动将标记插入其网页) - 只需“主”组件脚本文件。<script>

主流JavaScript库如何实现这一目标(Prototype,jQuery等)?这些工具是否将多个 JavaScript 文件合并到脚本文件的单个可再发行“构建”版本中?或者他们是否动态加载辅助的“库”脚本?

这个问题的补充:有没有办法在加载动态包含的JavaScript文件后处理事件?原型适用于文档范围的事件。例:document.observe

document.observe("dom:loaded", function() {
  // initially hide all containers for tab content
  $$('div.tabcontent').invoke('hide');
});

脚本元素有哪些可用事件?


答案 1

您可以使用原型动态创建脚本元素:

new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});

这里的问题是,我们不知道外部脚本文件何时完全加载。

我们经常希望我们的依赖代码在下一行,并希望编写如下内容:

if (iNeedSomeMore) {
    Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod();
    myFancyMethod(); // cool, no need for callbacks!
}

有一种智能方法可以注入脚本依赖项,而无需回调。您只需通过同步 AJAX 请求拉取脚本,并在全局级别评估脚本即可。

如果使用原型,Script.load 方法如下所示:

var Script = {
    _loadedScripts: [],
    include: function(script) {
        // include script only once
        if (this._loadedScripts.include(script)) {
            return false;
        }
        // request file synchronous
        var code = new Ajax.Request(script, {
            asynchronous: false,
            method: "GET",
            evalJS: false,
            evalJSON: false
        }).transport.responseText;
        // eval code on global level
        if (Prototype.Browser.IE) {
            window.execScript(code);
        } else if (Prototype.Browser.WebKit) {
            $$("head").first().insert(Object.extend(
                new Element("script", {
                    type: "text/javascript"
                }), {
                    text: code
                }
            ));
        } else {
            window.eval(code);
        }
        // remember included script
        this._loadedScripts.push(script);
    }
};

答案 2

在javascript中没有导入/包含/要求,但是有两种主要方法可以实现您想要的内容:

1 - 您可以使用 AJAX 调用加载它,然后使用 eval。

这是最直接的方法,但由于Javascript安全设置,它仅限于您的领域,使用eval正在为错误和黑客打开大门。

2 - 在 HTML 中添加具有脚本 URL 的脚本元素。

绝对是最好的方法。您甚至可以从外部服务器加载脚本,并且当您使用浏览器解析器评估代码时,它很干净。您可以将该元素放在网页的元素中,也可以放在 .scriptheadbody

这里讨论并说明了这两种解决方案。

现在,您必须了解一个大问题。这样做意味着您远程加载代码。现代 Web 浏览器将加载文件并继续执行当前脚本,因为它们异步加载所有内容以提高性能。

这意味着,如果您直接使用这些技巧,则在要求加载代码后,您将无法在下一行使用新加载的代码,因为它仍将加载。

例如:my_lovely_script.js包含 MySuperObject

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined

然后,按 F5 重新加载页面。它的工作原理!混乱。。。

那么该怎么办呢?

好吧,您可以使用作者在我给您的链接中建议的黑客。总之,对于赶时间的人,他在加载脚本时使用en event来运行回调函数。因此,您可以使用远程库将所有代码放在回调函数中。例如:

function loadScript(url, callback)
{
    // adding the script element to the head as suggested before
   var head = document.getElementsByTagName('head')[0];
   var script = document.createElement('script');
   script.type = 'text/javascript';
   script.src = url;

   // then bind the event to the callback function 
   // there are several events for cross browser compatibility
   script.onreadystatechange = callback;
   script.onload = callback;

   // fire the loading
   head.appendChild(script);
}

然后,在将脚本加载到 lambda 函数中后,编写要使用的代码:

var myPrettyCode = function() {
    // here, do what ever you want
};

然后你运行所有这些:

loadScript("my_lovely_script.js", myPrettyCode);

好吧,我明白了。但是写所有这些东西是很痛苦的。

好吧,在这种情况下,您可以一如既往地使用出色的免费jQuery框架,该框架可让您在一行中执行相同的操作:

$.getScript("my_lovely_script.js", function() {
    alert("Script loaded and executed.");
    // here you can use anything you defined in the loaded script
});