44

我习惯于使用 Java,其中(我们知道)每个对象都定义在自己的文件中(一般来说)。我喜欢这个。我认为它使代码更易于使用和管理。

我开始使用 javascript,我发现自己想为我在单个页面上使用的不同脚本使用单独的文件。我目前将自己限制在几个 .js 文件中,因为我担心如果我使用的更多,我将来会因为我目前无法预见的事情而感到不便。也许是循环引用?

简而言之,将我的脚本分成多个文件是不好的做法吗?

4

5 回答 5

26

2020 年更新:按照互联网标准,这个答案已经很老了,远非今天的全貌,但仍然偶尔会看到投票,所以我觉得有必要提供一些关于自发布以来发生的变化的提示。多年来对脚本加载的良好支持async、HTTP/2 的服务器推送功能以及对加载过程的一般浏览器优化,都对将 Javascript 分解为多个文件如何影响加载性能产生了影响。

对于那些刚开始使用 Javascript 的人,我的建议保持不变(使用捆绑器 / 缩小器并相信它默认做正确的事情),但对于任何找到这个问题的有更多经验的人,我会邀请他们调查async加载和服务器推送带来的新功能。

2013-ish的原始答案:


由于下载时间的原因,您应该始终尝试使您的脚本成为一个单一的大文件。但是,如果您使用缩小器(您应该这样做),它们可以为您将多个源文件合并为一个。因此,您可以继续处理多个文件,然后将它们缩小为单个文件以进行分发。

主要的例外是公共库,例如 jQuery,您应该始终从公共 CDN 加载它们(用户很可能已经加载了它们,因此不需要再次加载它们)。如果您确实使用公共 CDN,则始终在失败时从您自己的服务器加载备用。

正如评论中所指出的,真实的故事要复杂一些。

脚本可以同步 ( <script src="blah"></script>) 或异步 ( s=document.createElement('script');s.async=true;...) 加载。同步脚本会阻止加载其他资源,直到它们被加载。例如:

<script src="a.js"></script>
<script src="b.js"></script>

将请求 a.js,等待它加载,然后加载 b.js。在这种情况下,将 a.js 与 b.js 结合起来并一举加载它们显然会更好。

同样,如果 a.js 有加载 b.js 的代码,无论它们是否异步,您都会遇到相同的情况。

但是,如果您同时加载它们并且异步加载它们,并且取决于客户端与服务器的连接状态,以及只能通过分析才能真正确定的一大堆考虑因素,它可以更快。

(function(d){
    var s=d.getElementsByTagName('script')[0],f=d.createElement('script');
    f.type='text/javascript';
    f.async=true;
    f.src='a.js';
    s.parentNode.insertBefore(f,s);
    f=d.createElement('script');
    f.type='text/javascript';
    f.async=true;
    f.src='b.js';
    s.parentNode.insertBefore(f,s);
})(document)

它要复杂得多,但会同时加载 a.js 和 b.js 而不会相互阻塞或其他任何东西。最终,该async属性将被正确支持,并且您将能够像同步加载一样轻松地做到这一点。最终。

于 2013-03-13T22:55:22.100 回答
26

这里有很多正确的答案,这取决于您的应用程序的大小以及您将其交付给谁(由谁,我的意思是预期的设备等),以及您可以在服务器端做多少工作来确保您的目标是正确的设备(对于大多数非企业凡人来说,这距离 100% 可行还有很长的路要走)。

在构建您的应用程序时,“类”可以愉快地驻留在它们自己的文件中。
在跨文件拆分应用程序时,或者在处理具有过多假设的构造函数的类时(例如实例化其他类),循环引用或死端引用一个大问题。
有多种模式可以解决这个问题,但最好的模式当然是让您的应用程序考虑到 DI/IoC,这样就不会发生循环引用。
您还可以查看 require.js 或其他依赖加载程序。您需要获得的复杂程度取决于您的应用程序有多大,以及您希望所有内容有多私密。

在为您的应用程序提供服务时,提供 JS 的基线是连接您需要的所有脚本(以正确的顺序,如果您要实例化假设其他东西存在的东西),并将它们作为一个文件提供在底部这页纸。

但这是基线。
其他方法可能包括“延迟/延迟”加载。
加载所有你需要的东西来让页面提前工作。
同时,如果您的小程序或小部件在页面加载时不需要 100% 的功能,事实上,它们需要用户交互,或者在执行任何操作之前需要延迟,然后为这些加载脚本小部件延迟事件。在用户在选项卡上点击 mousedown 的位置加载选项卡式小部件的脚本。现在您只加载了您需要的脚本,并且仅在需要时加载,没有人会真正注意到下载的微小延迟。

将此与试图将 40,000 行应用程序填充到一个文件中的人进行比较。
只有一个 HTTP 请求,只有一个下载,但是解析/编译时间现在变成了明显的几分之一秒。

当然,延迟加载并不是将每个类留在自己的文件中的借口。
那时,您应该将它们打包成模块,并提供将运行整个小部件/小程序/任何东西的文件(除非有其他逻辑位置,直到以后才需要功能,并且它隐藏在进一步的交互之后)。

您还可以将这些模块的加载放在计时器上。
预先加载基线应用程序的东西(同样在页面底部,在一个文件中),然后设置半秒左右的超时时间,然后加载其他 JS 文件。
您现在不会妨碍页面的操作或用户移动的能力。这当然是最重要的部分。

于 2013-03-13T23:11:35.280 回答
4

这里有两个问题:a)易于开发 b)下载 JS 资产时的客户端性能

就开发而言,模块化从来都不是一件坏事。还有 Javascript 自动加载框架(如requireJSAMD)可用于帮助您管理模块及其依赖项。

但是,为了解决第二点,最好将所有 Javascript 合并到一个文件中并缩小它,这样客户端就不会花费太多时间下载所有资源。有一些工具 (requireJS) 也可以让您执行此操作(即,将所有依赖项组合到一个文件中)。

于 2013-03-13T22:55:10.240 回答
0

这取决于您现在使用的协议。如果您使用的是http2,我建议您拆分 js 文件。如果您使用 http,我建议您使用缩小的 js 文件。

这是使用httphttp2的网站示例

谢谢,希望对您有所帮助。

于 2016-11-25T09:18:36.163 回答
-4

这真的不要紧。如果您在多个文件中使用相同的 JavaScript,那么最好有一个包含 JavaScript 的文件可以从中获取。所以你只需要从一个地方更新脚本。

于 2013-03-13T22:56:39.643 回答