简体   繁体   English

我应该将我的 javascript 分成多个文件吗?

[英]Should I split my javascript into multiple files?

I'm used to working with Java in which (as we know) each object is defined in its own file (generally speaking).我习惯于使用 Java,其中(正如我们所知)每个对象都在自己的文件中定义(一般来说)。 I like this.我喜欢这个。 I think it makes code easier to work with and manage.我认为它使代码更易于使用和管理。

I'm beginning to work with javascript and I'm finding myself wanting to use separate files for different scripts I'm using on a single page.我开始使用 javascript,我发现自己想要为我在单个页面上使用的不同脚本使用单独的文件。 I'm currently limiting myself to only a couple .js files because I'm afraid that if I use more than this I will be inconvenienced in the future by something I'm currently failing to foresee.我目前将自己限制在几个 .js 文件中,因为我担心如果我使用的不止这些,我将来会因为我目前无法预见的事情而感到不便。 Perhaps circular references?也许循环引用?

In short, is it bad practice to break my scripts up into multiple files?简而言之,将我的脚本分成多个文件是不好的做法吗?

Update from 2020: this answer is very old by internet standards and is far from the full picture today, but still sees occasional votes so I feel the need to provide some hints on what has changed since it was posted. 2020 年更新:按照互联网标准,这个答案已经很老了,远非今天的全貌,但仍然偶尔会看到投票,所以我觉得有必要提供一些关于自发布以来发生了什么变化的提示。 Good support for async script loading, HTTP/2's server push capabilities, and general browser optimisations to the loading process over the years, have all had an impact on how breaking up Javascript into multiple files affects loading performance.多年来对async脚本加载的良好支持、HTTP/2 的服务器推送功能以及对加载过程的一般浏览器优化,都对将 Javascript 分解为多个文件如何影响加载性能产生了影响。

For those just starting out with Javascript, my advice remains the same (use a bundler / minifier and trust it to do the right thing by default), but for anybody finding this question who has more experience, I'd invite them to investigate the new capabilities brought with async loading and server push.对于那些刚开始使用 Javascript 的人,我的建议保持不变(使用捆绑器/压缩器并相信它在默认情况下会做正确的事情),但是对于任何有更多经验的人发现这个问题,我会邀请他们调查async加载和服务器推送带来的新功能。

Original answer from 2013-ish:来自 2013-ish 的原始答案:


Because of download times, you should always try to make your scripts a single, big, file.由于下载时间的原因,您应该始终尝试将脚本制作成单个大文件。 HOWEVER, if you use a minifier (which you should ), they can combine multiple source files into one for you.但是,如果您使用缩小器(您应该使用),它们可以为您将多个源文件合并为一个。 So you can keep working on multiple files then minify them into a single file for distribution.因此,您可以继续处理多个文件,然后将它们缩小为一个文件以进行分发。

The main exception to this is public libraries such as jQuery, which you should always load from public CDNs (more likely the user has already loaded them, so doesn't need to load them again).对此的主要例外是公共库,例如 jQuery,您应该始终从公共 CDN 加载它们(更有可能的是用户已经加载了它们,因此不需要再次加载它们)。 If you do use a public CDN, always have a fallback for loading from your own server if that fails.如果您确实使用公共 CDN,如果失败,请始终有一个从您自己的服务器加载的回退。

As noted in the comments, the true story is a little more complex;正如评论中所指出的,真实的故事要复杂一些;

Scripts can be loaded synchronously ( <script src="blah"></script> ) or asynchronously ( s=document.createElement('script');s.async=true;... ).脚本可以同步( <script src="blah"></script> )或异步( s=document.createElement('script');s.async=true;...s=document.createElement('script');s.async=true;... Synchronous scripts block loading other resources until they have loaded.同步脚本会阻止加载其他资源,直到它们加载完毕。 So for example:例如:

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

will request a.js, wait for it to load, then load b.js.将请求 a.js,等待它加载,然后加载 b.js。 In this case, it's clearly better to combine a.js with b.js and have them load in one fell swoop.在这种情况下,将 a.js 与 b.js 结合起来并让它们一举加载显然更好。

Similarly, if a.js has code to load b.js, you will have the same situation no matter whether they're asynchronous or not.同理,如果a.js有加载b.js的代码,不管异步与否,都会出现同样的情况。

But if you load them both at once and asynchronously, and depending on the state of the client's connection to the server, and a whole bunch of considerations which can only be truly determined by profiling, it can be faster.但是,如果您一次异步加载它们,并且取决于客户端与服务器的连接状态,以及只能通过分析才能真正确定的一大堆注意事项,它会更快。

(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)

It's much more complicated, but will load both a.js and b.js without blocking each other or anything else.它要复杂得多,但会同时加载 a.js 和 b.js 而不会相互阻塞或其他任何东西。 Eventually the async attribute will be supported properly, and you'll be able to do this as easily as loading synchronously.最终async属性将得到正确支持,您将能够像同步加载一样轻松地做到这一点。 Eventually.最终。

There are lots of correct answers, here, depending on the size of your application and whom you're delivering it to (by whom, I mean intended devices, et cetera), and how much work you can do server-side to ensure that you're targeting the correct devices (this is still a long way from 100% viable for most non-enterprise mortals).这里有很多正确的答案,这取决于您的应用程序的大小和您将其交付给谁(由谁,我指的是预期设备等),以及您可以在服务器端做多少工作来确保您的目标是正确的设备(对于大多数非企业用户来说,这距离 100% 可行还有很长的路要走)。

When building your application, "classes" can reside in their own files, happily.在构建应用程序时,“类”可以愉快地驻留在它们自己的文件中。
When splitting an application across files, or when dealing with classes with constructors that assume too much (like instantiating other classes), circular-references or dead-end references ARE a large concern.当跨文件拆分应用程序时,或者在处理具有假设过多的构造函数的类时(如实例化其他类),循环引用或死角引用一个大问题。
There are multiple patterns to deal with this, but the best one, of course is to make your app with DI/IoC in mind, so that circular-references don't happen.有多种模式可以解决这个问题,但最好的一种当然是让你的应用程序考虑到 DI/IoC,这样循环引用就不会发生。
You can also look into require.js or other dependency-loaders.您还可以查看 require.js 或其他依赖加载器。 How intricate you need to get is a function of how large your application is, and how private you would like everything to be.您需要获得的复杂程度取决于您的应用程序有多大,以及您希望一切都变得多么私密。

When serving your application, the baseline for serving JS is to concatenate all of the scripts you need (in the correct order, if you're going to instantiate stuff which assumes other stuff exists), and serve them as one file at the bottom of the page.在为您的应用程序提供服务时,为 JS 提供服务的基线是连接您需要的所有脚本(以正确的顺序,如果您要实例化假设其他内容存在的内容),并将它们作为一个文件提供给这一页。

But that's baseline.但这是基线。
Other methods might include "lazy/deferred" loading.其他方法可能包括“延迟/延迟”加载。
Load all of the stuff that you need to get the page working up-front.加载使页面预先工作所需的所有内容。
Meanwhile, if you have applets or widgets which don't need 100% of their functionality on page-load, and in fact, they require user-interaction, or require a time-delay before doing anything, then make loading the scripts for those widgets a deferred event.同时,如果您的小程序或小部件在页面加载时不需要 100% 的功能,并且实际上,它们需要用户交互,或者在做任何事情之前需要延迟,那么请为那些加载脚本小部件延迟事件。 Load a script for a tabbed widget at the point where the user hits mousedown on the tab.在用户在选项卡上按下鼠标时为选项卡式小部件加载脚本。 Now you've only loaded the scripts that you need, and only when needed, and nobody will really notice the tiny lag in downloading.现在您只加载了您需要的脚本,并且只在需要时加载,没有人会真正注意到下载过程中的微小延迟。

Compare this to people trying to stuff 40,000 line applications in one file.将此与试图在一个文件中填充 40,000 行应用程序的人进行比较。
Only one HTTP request, and only one download, but the parsing/compiling time now becomes a noticeable fraction of a second.只有一个 HTTP 请求,只有一个下载,但解析/编译时间现在变成了明显的几分之一秒。

Of course, lazy-loading is not an excuse for leaving every class in its own file.当然,延迟加载并不是将每个类都保留在自己的文件中的借口。
At that point, you should be packing them together into modules, and serving the file which will run that whole widget/applet/whatever (unless there are other logical places, where functionality isn't needed until later, and it's hidden behind further interactions).在这一点上,您应该将它们打包成模块,并提供将运行整个小部件/小程序/任何东西的文件(除非有其他逻辑位置,直到稍后才需要功能,并且它隐藏在进一步的交互后面)。

You could also put the loading of these modules on a timer.您还可以将这些模块的加载放在计时器上。
Load the baseline application stuff up-front (again at the bottom of the page, in one file), and then set a timeout for a half-second or so, and load other JS files.预先加载基线应用程序内容(再次在页面底部,在一个文件中),然后设置半秒左右的超时,并加载其他 JS 文件。
You're now not getting in the way of the page's operation, or of the user's ability to move around.您现在不会妨碍页面的操作或用户的移动能力。 This, of course is the most important part.这当然是最重要的部分。

There are two concerns here: a) ease of development b) client-side performance while downloading JS assets这里有两个问题:a) 易于开发 b) 下载 JS 资产时的客户端性能

As far as development is concerned, modularity is never a bad thing;就开发而言,模块化从来都不是坏事; there are also Javascript autoloading frameworks (like requireJS and AMD ) you can use to help you manage your modules and their dependencies.还有一些 Javascript 自动加载框架(如requireJSAMD )可用于帮助您管理模块及其依赖项。

However, to address the second point, it is better to combine all your Javascript into a single file and minify it so that the client doesn't spend too much time downloading all your resources.但是,为了解决第二点,最好将所有 Javascript 合并到一个文件中并缩小它,这样客户端就不会花太多时间下载所有资源。 There are tools (requireJS) that let you do this as well (ie, combine all your dependencies into a single file).有一些工具 (requireJS) 也可以让您执行此操作(即将所有依赖项合并到一个文件中)。

It's depending on the protocol you are using now.这取决于您现在使用的协议。 If you are using http2 , I suggest you to split the js file.如果您使用的是http2 ,我建议您拆分 js 文件。 If you use http, I advise you to use minified js file.如果您使用 http,我建议您使用缩小的 js 文件。

Here is the sample of website using http and http2这是使用httphttp2的网站示例

Thanks, hope it helps.谢谢,希望有帮助。

It does not really matter.这真的无所谓。 If you use the same JavaScript in multiple files, it can surely be good to have a file with the JavaScript to fetch from.如果您在多个文件中使用相同的 JavaScript,那么拥有一个包含 JavaScript 的文件来获取肯定会很好。 So you just need to update the script from one place.所以你只需要从一个地方更新脚本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM