我习惯于使用 Java,其中(我们知道)每个对象都定义在自己的文件中(一般来说)。我喜欢这个。我认为它使代码更易于使用和管理。
我开始使用 javascript,我发现自己想为我在单个页面上使用的不同脚本使用单独的文件。我目前将自己限制在几个 .js 文件中,因为我担心如果我使用的更多,我将来会因为我目前无法预见的事情而感到不便。也许是循环引用?
简而言之,将我的脚本分成多个文件是不好的做法吗?
我习惯于使用 Java,其中(我们知道)每个对象都定义在自己的文件中(一般来说)。我喜欢这个。我认为它使代码更易于使用和管理。
我开始使用 javascript,我发现自己想为我在单个页面上使用的不同脚本使用单独的文件。我目前将自己限制在几个 .js 文件中,因为我担心如果我使用的更多,我将来会因为我目前无法预见的事情而感到不便。也许是循环引用?
简而言之,将我的脚本分成多个文件是不好的做法吗?
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
属性将被正确支持,并且您将能够像同步加载一样轻松地做到这一点。最终。
这里有很多正确的答案,这取决于您的应用程序的大小以及您将其交付给谁(由谁,我的意思是预期的设备等),以及您可以在服务器端做多少工作来确保您的目标是正确的设备(对于大多数非企业凡人来说,这距离 100% 可行还有很长的路要走)。
在构建您的应用程序时,“类”可以愉快地驻留在它们自己的文件中。
在跨文件拆分应用程序时,或者在处理具有过多假设的构造函数的类时(例如实例化其他类),循环引用或死端引用是一个大问题。
有多种模式可以解决这个问题,但最好的模式当然是让您的应用程序考虑到 DI/IoC,这样就不会发生循环引用。
您还可以查看 require.js 或其他依赖加载程序。您需要获得的复杂程度取决于您的应用程序有多大,以及您希望所有内容有多私密。
在为您的应用程序提供服务时,提供 JS 的基线是连接您需要的所有脚本(以正确的顺序,如果您要实例化假设其他东西存在的东西),并将它们作为一个文件提供在底部这页纸。
但这是基线。
其他方法可能包括“延迟/延迟”加载。
加载所有你需要的东西来让页面提前工作。
同时,如果您的小程序或小部件在页面加载时不需要 100% 的功能,事实上,它们需要用户交互,或者在执行任何操作之前需要延迟,然后为这些加载脚本小部件延迟事件。在用户在选项卡上点击 mousedown 的位置加载选项卡式小部件的脚本。现在您只加载了您需要的脚本,并且仅在需要时加载,没有人会真正注意到下载的微小延迟。
将此与试图将 40,000 行应用程序填充到一个文件中的人进行比较。
只有一个 HTTP 请求,只有一个下载,但是解析/编译时间现在变成了明显的几分之一秒。
当然,延迟加载并不是将每个类留在自己的文件中的借口。
那时,您应该将它们打包成模块,并提供将运行整个小部件/小程序/任何东西的文件(除非有其他逻辑位置,直到以后才需要功能,并且它隐藏在进一步的交互之后)。
您还可以将这些模块的加载放在计时器上。
预先加载基线应用程序的东西(同样在页面底部,在一个文件中),然后设置半秒左右的超时时间,然后加载其他 JS 文件。
您现在不会妨碍页面的操作或用户移动的能力。这当然是最重要的部分。
这真的不要紧。如果您在多个文件中使用相同的 JavaScript,那么最好有一个包含 JavaScript 的文件可以从中获取。所以你只需要从一个地方更新脚本。