将javascript放在一个.js文件中或将其分解为多个.js文件?

时间:2009-02-17 06:28:03

标签: javascript

我的Web应用程序使用jQuery和一些jQuery插件(例如验证,自动完成)。我想知道是否应该将它们粘贴到一个.js文件中,以便可以更容易地缓存它,或者将它们分解为单独的文件,并且只包含我对给定页面所需的文件。

我还应该提一下,我关注的不仅是下载.js文件所需的时间,还包括根据加载的.js文件的内容减慢页面的速度。例如,添加自动完成插件往往会使我的基本测试的响应时间缩短100ms,即使在缓存时也是如此。我的猜测是它必须扫描DOM中导致这种延迟的元素。

11 个答案:

答案 0 :(得分:45)

我认为这取决于他们改变的频率。我们来看这个例子:

  • JQuery:每年更换一次
  • 第三方插件:每6个月更换一次
  • 您的自定义代码:每周更改

如果您的自定义代码仅代表总代码的10%,则您不希望用户每周下载其他90%的代码。你会分成至少2个js:JQuery +插件和你的自定义代码。现在,如果您的自定义代码占完整大小的90%,那么将所有内容放在一个文件中会更有意义。

当选择如何组合JS文件(和CSS相同)时,我平衡:

  • 文件的相对大小
  • 预期更新次数

答案 1 :(得分:30)

常见但相关的答案:

  

这取决于项目。

如果您有一个相当有限的网站,其中大部分功能在网站的多个部分重复使用,那么将所有脚本放在一个文件中是有意义的。

在我参与过的几个大型Web项目中,将公共站点范围的功能放在一个文件中并将更多特定于部分的功能放入自己的文件中更有意义。 (我们在这里讨论大型脚本文件,针对几个不同的网络应用程序的行为,所有这些都在同一个域下提供。)

将脚本拆分为单独文件的好处是,您不必为用户提供不使用的不必要内容和带宽。 (例如,如果他们从不访问网站上的“App A”,他们将永远不需要“App A”部分的100K脚本。但他们需要通用的站点范围功能。)

将脚本保存在一个文件中的好处是简单。服务器上的点击次数减少。用户下载次数减少。

像往常一样,YMMV。没有严格的规则。根据用户的用途,根据项目的结构,为用户做最有意义的事情。

答案 2 :(得分:2)

如果每个页面都需要这些文件,请将它们放在一个文件中。这将减少HTTP请求的数量,并将改善响应时间(对于大量访问)。

有关其他提示,请参阅Yahoo best practice

答案 3 :(得分:2)

我非常赞同bigmattyh说的,它确实依赖。

作为一般规则,我尝试尽可能地聚合脚本文件,但是如果你有一些脚本仅用于网站的一些区域,特别是那些在加载时执行大型DOM遍历的脚本,那么将它们留在单独的文件中是有意义的 例如如果您只在联系页面上使用验证,为什么要在主页上加载?

顺便说一下,你有时可以将这些文件隐藏到插页式页面,其中没有其他内容发生,所以当用户登陆需要它的其他非常繁重的页面时,它应该已经缓存 - 请谨慎使用 - 但是当你有人对你进行基准测试时,这可能是一个方便的技巧。

因此,尽可能少的脚本文件,在合理范围内。

如果您要发送一个100K的整体块,但只有80%的页面使用20K,请考虑拆分它。

答案 4 :(得分:1)

如果人们要访问您网站中的多个网页,最好将它们全部放在一个文件中,以便对其进行缓存。他们会预先考虑一次,但这将是他们在您的网站上花费的整个时间。

答案 5 :(得分:1)

在一天结束时,这取决于你。

但是,每个网页包含的信息越少,终端查看器下载的速度就越快。

如果您只包含每个页面所需的js文件,那么您的网站似乎更有效率和简化

答案 6 :(得分:1)

如果你喜欢用于开发的单独文件中的代码,你总是可以编写一个快速脚本,在缩小之前将它们连接成一个文件。

一个大文件更适合减少HTTP请求,正如其他海报所表明的那样。

答案 7 :(得分:1)

这在很大程度上取决于用户与您网站的互动方式。

您需要考虑的一些问题:

  • 第一页加载速度非常快有多重要?
  • 用户通常会将大部分时间花在网站的不同部分,并使用功能子集吗?
  • 您是否需要在页面准备就绪时准备好所有脚本,或者可以在页面加载后通过将<script>元素插入页面来加载一些脚本?

如果您真的想要提高性能,那么很好地了解用户如何使用您的网站以及您希望优化的内容是一个好主意。

但是,我的默认方法是将我的所有javascript连接并缩小为一个文件。 jQuery和jQuery.ui很小,开销很低。如果您使用的插件对页面加载时间有100ms的影响,则可能出现问题。

要检查的一些事项:

  • 您的HTTP服务器是否启用了gzipping?
  • 您是否在部署过程中生成具有唯一名称的静态文件?
  • 您是否正在提供永不停止缓存过期的静态文件?
  • 您是在页面顶部包含CSS还是在底部包含脚本?
  • 是否有一个更好(更小,更快)的jQuery插件可以做同样的事情?

答案 8 :(得分:0)

我也认为你应该采用单文件路线,正如其他人所建议的那样。但是,仅仅通过包含在你的大型js文件中,插件就会占用周期:

在执行昂贵的操作之前,请使用一些检查以确保您甚至在需要操作的页面上。也许您可以在运行自动完成插件之前检测dom节点的存在(或不存在),并且只在必要时初始化插件。没有必要在永远不需要某些功能的页面或部分上浪费dom遍历的开销。

在昂贵的代码块之前的简单条件将为您提供您所决定的两种方法的好处。

答案 9 :(得分:0)

我基本上已经到了将整个Web应用程序缩减为3个文件的地步。

  • vendor.js
  • app.js
  • app.css

供应商很整洁,因为它也具有所有样式。即我将所有供应商的CSS转换为最小的CSS,然后将其转换为javascript,并将其包含在vendor.js文件中。那也是在无礼之举之后。

因为我的供应商资料不经常更新,所以一旦投入生产,这种情况就很少见了。更新后,我只是将其重命名为vendor_1.0.0.js。

还有这些文件的简化版本。在开发人员中,我加载未缩小的版本,在生产环境中,我加载缩小的版本。

我使用gulp处理所有这些事情。使之成为可能的主要插件是......

  • gulp-include
  • gulp-css2js
  • gulp-concat
  • gulp-csso
  • gulp-html-to-js
  • gulp-mode
  • gulp重命名
  • gulp-uglify
  • node-sass-tilde-importer

现在这还包括我的图像,因为我使用了sass并且我有一个sass函数,可以将图像编译为css表中的数据URL。

function sassFunctions(options) {
options = options || {};
options.base = options.base || process.cwd();

var fs = require('fs');
var path = require('path');
var types = require('node-sass').types;

var funcs = {};

funcs['inline-image($file)'] = function (file, done) {
    var file = path.resolve(options.base, file.getValue());
    var ext = file.split('.').pop();
    fs.readFile(file, function (err, data) {
        if (err) return done(err);
        data = new Buffer(data);
        data = data.toString('base64');
        data = 'url(data:image/' + ext + ';base64,' + data + ')';
        data = types.String(data);
        done(data);
    });
};

return funcs;
}

因此,我的app.css将在CSS中包含所有应用程序图像,并且可以将图像添加到所需的任何样式中。通常,我为唯一的图像创建类,如果我希望它具有该图像,我将只使用该类的东西。我避免完全使用图片标签。

另外,使用html到js插件,我将所有js文件的html都编译为模板对象,该对象由html文件的路径(即“ html \ templates \ header.html”)进行散列,然后使用类似敲除的方法可以将该html数据绑定到一个或多个元素。

最终结果是,我可以得到一个完整的Web应用程序,该应用程序衍生出一个“ index.html”,其中没有任何内容,但这是:

<html>
<head>
    <script src="dst\vendor.js"></script>
    <script src="dst\app.css"></script>
    <script src="dst\app.js"></script>
</head>
<body id="body">
    <xyz-app params="//xyz.com/api/v1"></xyz-app>
    <script>
        ko.applyBindings(document.getTagById("body"));
    </script>
</body>
</html>

这将启动我的组件“ xyz-app”,它是整个应用程序,并且没有任何服务器端事件。它不能在PHP,DotNet Core MVC,MVC或任何其他东西上运行。它只是由诸如Gulp之类的构建系统管理的基本html,它需要数据的所有内容都是其余的api。

  • 身份验证-> Rest Api
  • 产品-> Rest Api
  • 搜索-> Google Compute Engine(用于索引来自其余api的内容的python api)。

所以我从来没有从服务器返回任何html(只是静态文件,这太疯狂了)。除index.html本身外,仅要缓存3个文件。 Web服务器支持默认文档(index.html),因此您仅会在URL中看到“ blah.com”,以及用于维护状态的任何查询字符串或哈希片段(用于标记URL的路由等)。

疯狂的快,所有等待运行它的JS引擎。

搜索优化比较棘手。这只是思考事物的另一种方式。即您让Google抓取了您的api,而不是您的物理网站,并且您告诉Google如何在每个结果上进入您的网站。

因此,假设您有一个ABC Thing的产品页面,其产品ID为129。Google将抓取您的产品api,以遍历所有产品并将它们编入索引。在其中,您的api在结果中返回一个url,告诉google如何在网站上获取该产品。即“ http://blah#products/129”。

因此,当用户搜索“ ABC物品”时,他们会看到列表,然后单击它就会带他们到“ http://blah#products/129”。

我认为搜索引擎需要开始变得越来越聪明,这是未来的imo。

我喜欢建立这样的网站,因为它摆脱了所有后端复杂性。您不需要RAZOR,PHP,Java,ASPX Web表单,也可以摆脱那些整个堆栈。...您所需要的只是编写其余api(WebApi2,Java Spring或w / e等)。

这将Web设计分为UI工程,后端工程和设计,并在它们之间创建了清晰的分隔。您可以让UX团队来构建整个应用程序,而架构团队可以完成所有其余的api工作,而无需这种方式的完整堆栈开发人员。

安全性也不是问题,因为您可以在ajax请求上传递凭据,并且如果您的内容都在同一个域中,则只需在根域上保存身份验证cookie即可(自动,无缝的SSO与您的所有其余的api)。

更不用说服务器场设置更简单了。负载平衡需求要少得多。交通能力要高得多。将其余api服务器群集在负载平衡器上比整个网站更容易。

只需设置1个nginx反向代理服务器即可提供索引.html并将api请求也定向到4个其余api服务器之一。

  • Api服务器1
  • Api服务器2
  • Api服务器3
  • Api服务器4

您的sql盒(已复制)仅从4个其余api服务器(如果可能的话,均使用SSD)获得负载平衡

  • Sql Box 1
  • Sql Box 2

您所有的服务器都可以在没有公共ip的内部网络上运行,而只需向反向代理服务器公开所有请求即可。

您可以在循环DNS上平衡反向代理服务器的负载。

这意味着您只需一个SSL证书,因为它是一个公共域。

如果您使用Google Compute Engine进行搜索和seo,那么它就在云端,因此不必担心,只需$。

答案 10 :(得分:-1)

我尝试在多个文件中破坏我的 JS,但遇到了问题。我有一个登录表单,我将其代码(AJAX 提交等)放入了自己的文件中。登录成功后,AJAX 回调会调用函数来显示其他页面元素。由于这些元素不是登录过程的一部分,我将它们的 JS 代码放在一个单独的文件中。问题是,除非先加载第二个文件,否则一个文件中的 JS 无法调用第二个文件中的函数(参见 Stack Overflow Q. 25962958),因此,在我的情况下,被调用的函数无法显示其他页面元素.有很多方法可以解决这个加载顺序问题(参见 Stack Overflow Q. 8996852),但我发现将所有代码放在一个更大的文件中更简单,并将属于同一功能组的代码部分清楚地分开和注释,例如将登录代码分开并清楚地注释为登录代码。