什么时候应该使用内联和外部 Javascript?

IT技术 javascript html performance frontend
2021-01-18 22:40:57

我想知道在性能和易于维护方面,我应该何时包含外部脚本或将它们与 html 代码内联编写。

对此的一般做法是什么?

真实世界场景 - 我有几个需要客户端表单验证的 html 页面。为此,我使用了一个包含在所有这些页面中的 jQuery 插件。但问题是,我是否:

  • 编写内联配置此脚本的代码?
  • 将所有位都包含在一个文件中,该文件在所有这些 html 页面之间共享?
  • 将每一位包含在一个单独的外部文件中,每个 html 页面一个?

谢谢。

6个回答

在最初发布此答案时(2008 年),规则很简单:所有脚本都应该是外部的。无论是维护还是性能。

(为什么是性能?因为如果代码是分开的,它可以更容易地被浏览器缓存。)

JavaScript 不属于 HTML 代码,如果它包含特殊字符(例如<, >),它甚至会产生问题。

如今,Web 可扩展性已经发生了变化。由于发出多个 HTTP 请求的延迟,减少请求数量已成为一个有效的考虑因素。这使答案变得更加复杂:在大多数情况下,仍然建议使用 JavaScript 外部但是对于某些情况,尤其是非常小的代码段,将它们内联到站点的 HTML 中是有意义的。

@Nick:大多数问题都可以克服。不过,最好不要一开始就生成它们。
2021-03-13 22:40:57
@callum Google 的用例与 99.999999% 的网站不同。当然,他们测量得非常仔细,即使是最小的差异也很重要。但是仅仅因为他们发现在他们的特定用例中,内联效果更好(可能是因为脚本更改非常频繁?)并不意味着我们可以从中推导出一般规则,甚至我们应该忽略“常规”规则(外部化脚本)。
2021-03-22 22:40:57
有时,内联时您会获得更好的性能。查看google.com的来源他们知道自己在做什么。
2021-03-23 22:40:57
@KonradRudolph - 同意,不应从 Google 的方法中推导出一般规则。我只是想暗示它可能值得质疑您的答案中规则无论如何,我认为谷歌这样做的原因是为了减少 HTTP 请求,这可能会使超过 0.000001% 的网站受益。带宽越来越高,但往返时间保持不变。删除整个串行 HTTP 请求有时比外部 JS 的缓存优势更好。当然取决于你的JS的大小。
2021-04-07 22:40:57
@callum 虽然这是真的,但关于缓存的观点仍然存在并且仍然很重要。仅当您的访问者不返回(然后您将无法获得足够的页面点击量以使其变得重要)或者您的内容更改如此频繁以至于缓存脚本文件没有任何好处时,减少往返次数才很重要。
2021-04-07 22:40:57

可维护性绝对是将它们保持在外部的一个原因,但是如果配置是单行的(或者通常比将这些文件置于外部所获得的 HTTP 开销要短),那么将它们保持内联在性能方面会更好。永远记住,每个 HTTP 请求都会在执行时间和流量方面产生一些开销。

自然而然,当您的代码长于几行并且并非真正特定于单个页面时,这一切都变得无关紧要。当您希望能够重用该代码时,请将其设为外部。如果你不这样做,看看它的大小,然后再决定。

这是我的担忧之一。对几行代码进行单独的 HTTP 请求似乎很浪费。
2021-03-24 22:40:57
@HorstGutmann 如何使文件具有可维护性的外部帮助?我个人更喜欢尽可能使用外部 js,但是是否有一些客观的东西可以使其更易于维护?
2021-03-29 22:40:57
您能否为您的代码发布示例配置?IMO 如果它少于 300 个字符并且绝对特定于页面,则将其内联。
2021-04-05 22:40:57
这应该是最重要的答案imo
2021-04-06 22:40:57
@Dan 请记住,单独的请求仅在第一次发生。如果您希望您的用户多次加载页面,那么缓存外部(即使是几行)显然比在 n=2+ 页面加载时等待网络上那几行的字节要快。
2021-04-09 22:40:57

外化 javascript 是雅虎性能规则之一:http : //developer.yahoo.com/performance/rules.html#external

虽然您应该始终将脚本外部化的硬性规则通常是一个不错的选择,但在某些情况下,您可能希望内联某些脚本和样式。但是,您应该只内联您知道会提高性能的内容(因为您已经对此进行了测量)。

此外,如上所述,HTTP/2 也改变了“1 次调用”的做法。
2021-03-14 22:40:57
我认为雅虎也建议将所有 Javascript 添加到一个 HTTP 调用中——但这并不意味着在开发过程中脚本应该都在同一个文件中
2021-03-15 22:40:57

如果你只关心性能,这个线程中的大部分建议都是完全错误的,并且在 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 兆字节的压缩代码,很明显,至少不应再内联公共库。

@BornToCode 这个想法是在服务器端有事情做的同时给客户端做一些事情。因为需要解释客户端库 - 最好在服务器上进行任何计算之前启动该过程摊销窗口是客户端处理 JS 所需的时间。如果你精心设计了一个 2 级火箭,你就可以免费获得那个窗口。
2021-03-12 22:40:57
我没有得到现在是 <dynamic> 部分部分的服务器端处理的摊销窗口- 服务器处理它需要的任何东西,然后才提供整个渲染的 html(头部 + 正文),其他服务器处理什么之后需要吗?
2021-03-26 22:40:57

我认为特定于一页的短脚本案例是(仅)内联脚本的可辩护案例