如何可靠地动态加载JavaScript文件?这将用于实现一个模块或组件,当'初始化'时,组件将根据需要动态加载所有需要的JavaScript库脚本 .
使用该组件的客户端不需要加载实现此组件的所有库脚本文件(并手动将 <script>
标记插入其网页) - 只需'main'组件脚本文件 .
How do mainstream JavaScript libraries accomplish this (Prototype, jQuery, etc)? 这些工具是否将多个JavaScript文件合并为一个可再发行的'build'版本的脚本文件?或者他们是否动态加载辅助'library'脚本?
此问题的补充: is there a way to handle the event after a dynamically included JavaScript file is loaded? 原型具有 document.observe
用于文档范围的事件 . 例:
document.observe("dom:loaded", function() {
// initially hide all containers for tab content
$$('div.tabcontent').invoke('hide');
});
What are the available events for a script element?
24 回答
您可以编写动态脚本标记(使用Prototype):
这里的问题是我们不知道外部脚本文件何时完全加载 .
我们经常希望我们的依赖代码在下一行,并喜欢写下这样的东西:
有一种智能方法可以在不需要回调的情况下注入脚本依赖项 . 您只需通过同步AJAX请求拉出脚本并在全局级别上评估脚本 .
如果使用Prototype,则Script.load方法如下所示:
javascript中没有import / include / require,但有两种主要方法可以实现您的目标:
1 - 您可以使用AJAX调用加载它,然后使用eval .
这是最直接的方式,但由于Javascript安全设置,它仅限于您的域,并且使用eval可以打开错误和黑客的大门 .
2 - 在HTML中添加带脚本URL的脚本标记 .
绝对是最好的方式 . 您甚至可以从外部服务器加载脚本,并且在使用浏览器解析器评估代码时它是干净的 . 您可以将标记放在网页的头部或主体的底部 .
这里讨论和说明了这两种解决方案 .
现在,您必须了解一个大问题 . 这样做意味着您远程加载代码 . 现代Web浏览器将加载文件并继续执行当前脚本,因为它们异步加载所有内容以提高性能 .
这意味着如果你直接使用这些技巧,在你要求加载后,你将无法在下一行使用新加载的代码,因为它仍然会加载 .
E.G:my_lovely_script.js包含MySuperObject
然后你重新加载页面击中F5 . 它的工作原理!混乱...
那该怎么办呢?
好吧,你可以在我给你的链接中使用作者建议的黑客 . 总之,对于匆忙的人,他在加载脚本时使用en事件来运行回调函数 . 因此,您可以使用远程库将所有代码放在回调函数中 . E.G:
然后在lambda函数中加载脚本后编写要使用的代码:
然后你运行所有:
好,我知道了 . 但写这些东西真是太痛苦了 .
那么,在这种情况下,你可以像往常一样使用梦幻般的免费jQuery框架,它让你在一行中做同样的事情:
我使用much less complicated version recently和jQuery:
它在我测试的每个浏览器中都运行良好:IE6 / 7,Firefox,Safari,Opera .
Update: jQuery-less版本:
我做的基本上与你做亚当的事情相同,但稍加修改以确保我附加到head标签以完成工作 . 我只是创建了一个include函数(下面的代码)来处理脚本和css文件 .
此函数还会检查以确保尚未动态加载脚本或CSS文件 . 它不检查手动编码值,并且可能有更好的方法来做到这一点,但它达到了目的 .
另一个很棒的答案
https://stackoverflow.com/a/950146/671046
以下是我发现的一些示例代码...有没有人有更好的方法?
如果你已经加载了jQuery,你应该使用$.getScript .
这比其他答案有一个优势,因为你有一个内置的回调函数(以保证在依赖代码运行之前加载脚本),你可以控制缓存 .
我认为只需将脚本添加到正文然后将其添加到页面的最后一个节点就更容易了 . 这个怎么样:
一个荒谬的单行,对于那些认为加载js库的人不应该使用多行代码:P
显然,如果要导入的脚本是模块,则可以使用import(...)函数 .
我已经使用了我在网上发现的另一种解决方案......这个是在creativecommons下它 checks if the source was included prior to calling the function ...
你可以在这里找到这个文件:include.js
刚刚发现YUI 3中的一个很棒的功能(在预览版中可用时) . 您可以轻松地将依赖项插入YUI库和"external"模块(您正在寻找的内容),而无需太多代码:YUI Loader .
它还会在加载外部模块后立即回答有关正在调用的函数的第二个问题 .
例:
完美地为我工作,并具有管理依赖关系的优势 . 有关example with YUI 2 calendar,请参阅YUI文档 .
如果要加载 SYNC 脚本,则需要将脚本文本直接添加到HTML HEAD标记 . 添加它将触发 ASYNC 加载 . 要同步从外部文件加载脚本文本,请使用XHR . 下面是一个快速示例(它正在使用此帖和其他帖子中的其他部分答案):
我们在工作中使用的技术是使用AJAX请求请求javascript文件,然后使用eval()返回 . 如果您正在使用原型库,则它们在Ajax.Request调用中支持此功能 .
jquery resolved this for me with its .append() function - 用于加载完整的jquery ui包
To Use - 在导入jquery.js之后在你的html / php / etc的头部,你只需要包含这样一个文件就可以加载到你的库的整个库中......
保持简洁,简洁,可维护! :]
此代码只是一个简短的功能示例,可能需要其他功能,以便在任何(或给定)平台上提供全面支持 .
有专门为此目的而设计的脚本 .
yepnope.js内置于Modernizr中,lab.js是一个更优化(但用户友好版本较少) .
我不会建议通过像jquery或prototype这样的大型库来实现这一点 - 因为脚本加载器的一个主要好处是能够尽早加载脚本 - 你不必等到jquery和你所有的dom元素加载之前运行检查以查看是否要动态加载脚本 .
我编写了一个简单的模块,可以自动执行在JavaScript中导入/包含模块脚本的工作 . 试一试,请多给一些反馈! :)有关代码的详细说明,请参阅此博客文章:http://stamat.wordpress.com/2013/04/12/javascript-require-import-include-modules/
我迷失在所有这些样本中,但今天我需要从我的主.js加载外部.js,我这样做了:
Here是一个简单的回调和IE支持:
所有主要的javascript库,如jscript,prototype,YUI都支持加载脚本文件 . 例如,在YUI中,加载核心后,您可以执行以下操作来加载日历控件
我知道我的答案对于这个问题来说有点迟了,但是,这是 www.html5rocks.com 中的一篇很棒的文章 - Deep dive into the murky waters of script loading .
在该文章中得出的结论是,在浏览器支持方面,动态加载JavaScript文件而不阻止内容呈现的最佳方法是以下方式:
考虑到您有四个名为
script1.js, script2.js, script3.js, script4.js
的脚本,那么您可以使用 applying async = false 执行此操作:现在, Spec says :一起下载,所有下载后立即执行 .
Firefox < 3.6, Opera says: 我不知道这个“异步”的东西是什么,但事实上,我按照添加的顺序执行通过JS添加的脚本 .
Safari 5.0 says: 我理解“异步”,但不明白用JS将其设置为“false” . 我会在他们降落后立即以任何顺序执行你的脚本 .
IE < 10 says: 不知道“异步”,但有一个使用“onreadystatechange”的解决方法 .
Everything else says: 我是你的朋友,我们将通过这本书来做这件事 .
Now, the full code with IE < 10 workaround:
A few tricks and minification later, it’s 362 bytes
像这样......
这是一个加载JS文件的函数的简单示例 . 相关要点:
你不需要jQuery,所以你最初可以使用它来加载jQuery.js文件
与回调异步
它确保它只加载一次,因为它使机箱保留了加载URL的记录,从而避免使用网络
与jQuery
$.ajax
或$.getScript
相反,您可以使用nonce,从而解决了CSPunsafe-inline
的问题 . 只需使用属性script.nonce
现在你只需使用它
有一个新的提议ECMA标准名为dynamic import,最近并入Chrome和Safari .