我想知道在性能和易于维护方面,我应该何时包含外部脚本或将它们与 html 代码内联编写。
对此的一般做法是什么?
真实世界场景 - 我有几个需要客户端表单验证的 html 页面。为此,我使用了一个包含在所有这些页面中的 jQuery 插件。但问题是,我是否:
- 编写内联配置此脚本的代码?
- 将所有位都包含在一个文件中,该文件在所有这些 html 页面之间共享?
- 将每一位包含在一个单独的外部文件中,每个 html 页面一个?
谢谢。
我想知道在性能和易于维护方面,我应该何时包含外部脚本或将它们与 html 代码内联编写。
对此的一般做法是什么?
真实世界场景 - 我有几个需要客户端表单验证的 html 页面。为此,我使用了一个包含在所有这些页面中的 jQuery 插件。但问题是,我是否:
谢谢。
在最初发布此答案时(2008 年),规则很简单:所有脚本都应该是外部的。无论是维护还是性能。
(为什么是性能?因为如果代码是分开的,它可以更容易地被浏览器缓存。)
JavaScript 不属于 HTML 代码,如果它包含特殊字符(例如<
, >
),它甚至会产生问题。
如今,Web 可扩展性已经发生了变化。由于发出多个 HTTP 请求的延迟,减少请求数量已成为一个有效的考虑因素。这使答案变得更加复杂:在大多数情况下,仍然建议使用 JavaScript 外部。但是对于某些情况,尤其是非常小的代码段,将它们内联到站点的 HTML 中是有意义的。
可维护性绝对是将它们保持在外部的一个原因,但是如果配置是单行的(或者通常比将这些文件置于外部所获得的 HTTP 开销要短),那么将它们保持内联在性能方面会更好。永远记住,每个 HTTP 请求都会在执行时间和流量方面产生一些开销。
自然而然,当您的代码长于几行并且并非真正特定于单个页面时,这一切都变得无关紧要。当您希望能够重用该代码时,请将其设为外部。如果你不这样做,看看它的大小,然后再决定。
外化 javascript 是雅虎性能规则之一:http : //developer.yahoo.com/performance/rules.html#external
虽然您应该始终将脚本外部化的硬性规则通常是一个不错的选择,但在某些情况下,您可能希望内联某些脚本和样式。但是,您应该只内联您知道会提高性能的内容(因为您已经对此进行了测量)。
如果你只关心性能,这个线程中的大部分建议都是完全错误的,并且在 SPA 时代变得越来越错误,我们可以假设没有 JS 代码的页面是无用的。我花了无数个小时优化 SPA 页面加载时间,并使用不同的浏览器验证这些结果。通过重新编排您的 html,全面提高性能可能会非常引人注目。
为了获得最佳性能,您必须将页面视为两级火箭。这两个阶段大致对应于<head>
和<body>
阶段,但可以将它们视为<static>
和<dynamic>
。静态部分基本上是一个字符串常量,您可以尽可能快地将其推下响应管道。如果您使用大量设置 cookie 的中间件(这些需要在发送 http 内容之前设置),这可能会有点棘手,但原则上它只是刷新响应缓冲区,希望在跳转到一些模板代码(razor、php、等)在服务器上。这听起来可能很难,但我只是解释错了,因为它几乎是微不足道的。您可能已经猜到,这个静态部分应该包含所有内联和缩小的 javascript。它看起来像
<!DOCTYPE html>
<html>
<head>
<script>/*...inlined jquery, angular, your code*/</script>
<style>/* ditto css */</style>
</head>
<body>
<!-- inline all your templates, if applicable -->
<script type='template-mime' id='1'></script>
<script type='template-mime' id='2'></script>
<script type='template-mime' id='3'></script>
由于通过线路发送这部分几乎没有任何成本,因此您可以预期客户端将在连接到服务器后大约 5 毫秒 + 延迟的某个地方开始接收它。假设服务器合理关闭,此延迟可能在 20 毫秒到 60 毫秒之间。浏览器将在收到此部分后立即开始处理,处理时间通常会以 20 倍或更多的因素支配传输时间,现在这是服务器端处理该<dynamic>
部分的分摊窗口。
浏览器(chrome,rest 可能慢 20%)大约需要 50 毫秒来处理内联 jquery + signalr + angular + ng animate + ng touch + ng routes + lodash。这本身就非常了不起。大多数网络应用程序的代码比所有那些流行的库加在一起都要少,但假设你有同样多的代码,所以我们将赢得延迟 + 100 毫秒的客户端处理(这个延迟胜利来自第二个传输块)。当第二个块到达时,我们已经处理了所有 js 代码和模板,我们可以开始执行 dom 转换。
您可能会反对这种方法与内联概念正交,但事实并非如此。如果您不是内联,而是链接到 cdns 或您自己的服务器,则浏览器将不得不打开另一个连接并延迟执行。由于此执行基本上是免费的(因为服务器端正在与数据库对话),因此必须清楚所有这些跳转比根本不执行跳转的成本更高。如果有一个浏览器怪癖说外部 js 执行得更快,我们可以衡量哪个因素占主导地位。我的测量表明,在这个阶段额外的请求会降低性能。
我在优化 SPA 应用程序方面做了很多工作。人们普遍认为数据量很重要,而实际上延迟和执行通常占主导地位。我列出的缩小的库加起来有 300kb 的数据,这只是 68kb gzipped,或者在 2mbit 3g/4g 手机上下载 200ms,这正是在同一部手机上检查它是否有相同数据所需要的延迟已经在它的缓存中,即使它被代理缓存,因为移动延迟税(电话到塔延迟)仍然适用。同时,具有较低首跳延迟的桌面连接通常具有更高的带宽。
简而言之,现在(2014 年),最好内联所有脚本、样式和模板。
编辑(2016 年 5 月)
随着 JS 应用程序的不断增长,我的一些有效负载现在堆积了多达 3 兆字节的压缩代码,很明显,至少不应再内联公共库。
我认为特定于一页的短脚本案例是(仅)内联脚本的可辩护案例