如何在另一个js文件中引入js文件?

285

如何在另一个js文件中包含一个js文件,以遵循DRY原则并避免重复代码。


3
可能是包含一个.js文件在另一个.js文件中的重复问题,或者是这个问题 - user113716
现在看来,这个似乎是规范的重复选择。 - ggorlen
4个回答

302

您只能在HTML页面中包含脚本文件,而不能��其他脚本文件中包含。话虽如此,您可以编写JavaScript代码将您的“已包含”脚本加载到同一页面中:

var imported = document.createElement('script');
imported.src = '/path/to/imported/script';
document.head.appendChild(imported);

你的代码很可能依赖于你所谓的“包含”脚本,但如果浏览器异步加载“导入”的脚本,则可能会失败。最好的方法是使用第三方库,如jQuery或YUI,这将为您解决此问题。

// jQuery
$.getScript('/path/to/imported/script.js', function()
{
    // script is now loaded and executed.
    // put your dependent JS here.
});

7
我只能重申一遍:如果使用$.getScript,第二个依赖脚本将在第一个脚本加载并执行后开始加载。这是顺序而非并行加载。此外,如果有人通过<script>包含loader.js文件,该文件会加载某些JavaScript库(比如jQuery UI),那么下一个<script>中不能直接加载使用该库的main.js。因此,使用JavaScript库不像通常那样简单。为了理解:我想使用这种方法,但需要建议其他更实用的方法。 - Oleg
如果您的第一个建议,需要使用 imported.onload 来级联脚本。但是,如果我们继续遇到我所描述的相同问题,则需要考虑其他解决方案。 - Oleg
2
如果您使用例如Google Chrome的开发者工具的“时间轴”,则可以验证http://www.ok-soft-gmbh.com/jqGrid/iedeveloper.htm使用 document.writeln 并行加载脚本并以相同正确的顺序执行(评估)。该页面是XHTML格式,因此来自https://dev59.com/l3RA5IYBdhLWcg3w2xwI的第一条语句也是错误的。因此没有找到理由(我可以验证)**为什么**在位于 <head> 中的<script> 的内部使用document.writeln 是不好的。我希望有人可以给我发布一个解释。 - Oleg
2
根据这份文档 https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script,在使用 document.createElement() 时,你可以指定 async="false" 来强制加载同步。这似乎解决了使用该方法的问题。 - Steve Waring
然而,当我在appendChild之后使用alert进行测试,并将插入的脚本作为第一行使用alert时,来自插入脚本的警报排在第二位,因此它不是同步加载。 - Steve Waring

21

我不赞同使用document.write技术(参见Vahan Margaryan的建议)。我喜欢document.getElementsByTagName('head')[0].appendChild(...)(参见Matt Ball的建议),但是有一个重要的问题:脚本执行顺序

最近,我花了很多时间复现一个类似的问题one similar issue,甚至知名的jQuery插件也使用了相同的技术(查看src here)来加载文件,但其他人也报告了这个问题。想象一下,你有一个由许多脚本组成的JavaScript库,其中一个loader.js加载所有部分。有些部分是彼此依赖的。想象一下,你在<script>中包含另一个main.js脚本,该脚本紧接着使用loader.js中的对象。问题是有时main.jsloader.js加载所有脚本之前就已经执行了。在main.js脚本中使用$(document).ready(function () {/*code here*/});并不能解决问题。在loader.js中使用级联的onload事件处理程序将使脚本加载变成顺序而不是并行,并且将使使用main.js脚本变得困难,因为它应该只是在loader.js之后的某个位置进行包含。

通过在我的环境中复制问题,我可以看到在包含JavaScript时Internet Explorer 8脚本的执行顺序可能会有所不同。如果您需要包含彼此依赖的脚本,则这是一个非常棘手的问题。该问题在并行加载JavaScript文件中有描述,并建议使用document.writeln来解决。
document.writeln("<script type='text/javascript' src='Script1.js'></script>");
document.writeln("<script type='text/javascript' src='Script2.js'></script>");

在“脚本并行下载但按照写入到页面的顺序执行”的情况下,从使用document.getElementsByTagName('head')[0].appendChild(...)技术转换到document.writeln后,我再也没有看到这个问题了。

因此,我建议您使用document.writeln

更新:如果有人感兴趣,他们可以在Internet Explorer中加载(和重新加载)the page(该页面使用document.getElementsByTagName('head')[0].appendChild(...)技术),然后与the fixed version使用document.writeln进行比较。(页面的代码相对不太规范,不是我的,但可用于重现该问题)。


8

您需要编写一个document.write对象:

document.write('<script type="text/javascript" src="file.js" ></script>');

将其放置在您的主javascript文件中


24
噫,切勿提倡使用 document.write() - Matt Ball
15
@Matt Ball:你说得没错,但既然Vahan是新来的,你可能需要解释一下为什么。 - Konerak
12
@Konerak: 这里是为什么 - Matt Ball
4
我不同意对document.write的批评。我在回答中写了更多信息。 - Oleg
请避免使用document.write,这已经是一个不好的编程模式。 - Simos Fasouliotis
显示剩余4条评论

6

这是不可能直接实现的。你可以编写一些预处理器来处理它。

如果我理解正确,以下内容可能有助于实现此目标:

  • 使用预处理器,例如运行JS文件时查找类似 "@import somefile.js" 的模式,并将其替换为实际文件的内容。Nicholas Zakas(Yahoo)编写了一个Java库,您可以使用它(http://www.nczonline.net/blog/2009/09/22/introducing-combiner-a-javascriptcss-concatenation-tool/)。

  • 如果您正在使用Ruby on Rails,则可以尝试使用Jammit资源打包,它使用assets.yml配置文件,在其中可以定义包含多个文件的包,并通过包名称在实际网页中引用它们。

  • 尝试使用像RequireJS这样的模块加载器或LabJs这样的脚本加载器,具有控制加载顺序和利用并行下载的能力。

目前 JavaScript 没有像 CSS (@import) 那样提供将一个 JavaScript 文件包含到另一个文件中的 "本地" 方式,但是上述提到的所有工具/方法都可以帮助实现您提到的 DRY 原则。如果您来自服务器端背景,可能会感觉不直观,但这就是事实。对于前端开发人员,这个问题通常是一个 "部署和打包问题"。
希望能帮到您。

请问您能否举个例子? - Aditya Shukla
我编辑了我的回答,以更好地解释我的想法。希望这次我表达得足够清楚。 - Arnab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接