【问题标题】:Should CSS always precede Javascript?CSS 应该总是在 Javascript 之前吗?
【发布时间】:2012-03-05 11:45:15
【问题描述】:

在网上的无数地方,我都看到了在 JavaScript 之前包含 CSS 的建议。推理一般是,of this form

在订购 CSS 和 JavaScript 时,您需要自己的 CSS 先来。原因是渲染线程拥有所有 呈现页面所需的样式信息。如果 JavaScript 包含在先,JavaScript引擎必须先解析它 继续下一组资源。这意味着渲染 线程不能完全显示页面,因为它没有所有 它需要的样式。

我的实际测试揭示了一些完全不同的东西:

我的测试工具

我使用以下 Ruby 脚本为各种资源生成特定的延迟:

require 'rubygems'
require 'eventmachine'
require 'evma_httpserver'
require 'date'

class Handler  < EventMachine::Connection
  include EventMachine::HttpServer

  def process_http_request
    resp = EventMachine::DelegatedHttpResponse.new( self )

    return unless @http_query_string

    path = @http_path_info
    array = @http_query_string.split("&").map{|s| s.split("=")}.flatten
    parsed = Hash[*array]

    delay = parsed["delay"].to_i / 1000.0
    jsdelay = parsed["jsdelay"].to_i

    delay = 5 if (delay > 5)
    jsdelay = 5000 if (jsdelay > 5000)

    delay = 0 if (delay < 0) 
    jsdelay = 0 if (jsdelay < 0)

    # Block which fulfills the request
    operation = proc do
      sleep delay 

      if path.match(/.js$/)
        resp.status = 200
        resp.headers["Content-Type"] = "text/javascript"
        resp.content = "(function(){
            var start = new Date();
            while(new Date() - start < #{jsdelay}){}
          })();"
      end
      if path.match(/.css$/)
        resp.status = 200
        resp.headers["Content-Type"] = "text/css"
        resp.content = "body {font-size: 50px;}"
      end
    end

    # Callback block to execute once the request is fulfilled
    callback = proc do |res|
        resp.send_response
    end

    # Let the thread pool (20 Ruby threads) handle request
    EM.defer(operation, callback)
  end
end

EventMachine::run {
  EventMachine::start_server("0.0.0.0", 8081, Handler)
  puts "Listening..."
}

上面的迷你服务器允许我为 JavaScript 文件(服务器和客户端)设置任意延迟和任意 CSS 延迟。例如,http://10.0.0.50:8081/test.css?delay=500 给了我 500 毫秒的 CSS 传输延迟。

我使用以下页面进行测试。

<!DOCTYPE html>
<html>
  <head>
      <title>test</title>
      <script type='text/javascript'>
          var startTime = new Date();
      </script>
      <link href="http://10.0.0.50:8081/test.css?delay=500" type="text/css" rel="stylesheet">
      <script type="text/javascript" src="http://10.0.0.50:8081/test2.js?delay=400&amp;jsdelay=1000"></script> 
  </head>
  <body>
    <p>
      Elapsed time is: 
      <script type='text/javascript'>
        document.write(new Date() - startTime);
      </script>
    </p>    
  </body>
</html>

当我首先包含 CSS 时,页面需要 1.5 秒才能呈现:

当我首先包含 JavaScript 时,页面需要 1.4 秒才能呈现:

我在 Chrome、Firefox 和 Internet Explorer 中得到了类似的结果。然而,在 Opera 中,顺序并不重要。

似乎正在发生的事情是,JavaScript 解释器在所有 CSS 下载完成之前拒绝启动。因此,似乎先包含 JavaScript 会更有效,因为 JavaScript 线程会获得更多运行时间。

我是否遗漏了什么,将 CSS 包含在 JavaScript 包含之前的建议是否不正确?

很明显,我们可以添加异步或使用 setTimeout 来释放渲染线程或将 JavaScript 代码放在页脚中,或者使用 JavaScript 加载器。这里的重点是关于头部中基本 JavaScript 位和 CSS 位的排序。

【问题讨论】:

  • 1511 与 1422 的差异是否具有统计学意义?那是百分之六。显着与平均人类表现差异的一般阈值约为 20%。
  • 重点是重新排序消除了这种任意延迟,您可以将延迟设置为您想要的任何内容,它只是问题的演示。
  • 你的延迟是 100 毫秒吗?您的屏幕截图中的差异是 89 毫秒。在您的 URL 中,它是 delay=400&amp;amp;jsdelay=1000delay=500,这与 100 毫秒或 89 毫秒相差甚远。我想我不清楚你指的是哪些数字。
  • "如果 Javascript 包含在前,则 Javascript 引擎必须在继续处理下一组资源之前将其全部解析。这意味着渲染线程无法完全显示页面,因为它没有它需要的所有样式。” - 如果 JS 包含在头部,那么 JS 将在页面呈现之前执行,无论 CSS 包含是在之前还是之后。跨度>
  • 不确定您是否考虑过这一点,但加载时间的感知也很重要。因此,例如,如果首先加载 CSS 甚至只为您提供页面背景颜色/纹理,它似乎会更快。绝对加载时间可能无法说明这一点。

标签: javascript css performance


【解决方案1】:

这是一个非常有趣的问题。我总是把我的 CSS &lt;link href="..."&gt;s 放在我的 JS &lt;script src="..."&gt;s 之前,因为“我读过一次它更好。”所以,你是对的;现在是我们进行实际研究的时候了!

我在 Node 中设置了自己的测试工具(代码如下)。基本上,我:

  • 确保没有 HTTP 缓存,因此每次加载页面时浏览器都必须进行完整下载。
  • 为了模拟现实,我加入了 jQuery 和 H5BP CSS(因此有相当数量的脚本/CSS 需要解析)
  • 设置两个页面 - 一个在脚本前使用 CSS,一个在脚本后使用 CSS。
  • 记录了&lt;head&gt;中的外部脚本执行所用的时间
  • 记录&lt;body&gt;中的内联脚本执行的时间,类似于DOMReady
  • 延迟向浏览器发送 CSS 和/或脚本 500 毫秒。
  • 在 3 种主流浏览器中运行了 20 次测试。

结果

首先,将 CSS 文件延迟 500 毫秒:

     Browser: Chrome 18    | IE 9         | Firefox 9
         CSS: first  last  | first  last  | first last
=======================================================
Header Exec |              |              |
Average     | 583ms  36ms  | 559ms  42ms  | 565ms 49ms
St Dev      | 15ms   12ms  | 9ms    7ms   | 13ms  6ms
------------|--------------|--------------|------------
Body Exec   |              |              |
Average     | 584ms  521ms | 559ms  513ms | 565ms 519ms
St Dev      | 15ms   9ms   | 9ms    5ms   | 13ms  7ms

接下来,我将 jQuery 设置为延迟 500 毫秒,而不是 CSS:

     Browser: Chrome 18    | IE 9         | Firefox 9
         CSS: first  last  | first  last  | first last
=======================================================
Header Exec |              |              |
Average     | 597ms  556ms | 562ms  559ms | 564ms 564ms
St Dev      | 14ms   12ms  | 11ms   7ms   | 8ms   8ms
------------|--------------|--------------|------------
Body Exec   |              |              |
Average     | 598ms  557ms | 563ms  560ms | 564ms 565ms
St Dev      | 14ms   12ms  | 10ms   7ms   | 8ms   8ms

最后,我将 both jQuery 和 CSS 设置为延迟 500 毫秒:

     Browser: Chrome 18    | IE 9         | Firefox 9
         CSS: first  last  | first  last  | first last
=======================================================
Header Exec |              |              |
Average     | 620ms  560ms | 577ms  577ms | 571ms 567ms
St Dev      | 16ms   11ms  | 19ms   9ms   | 9ms   10ms
------------|--------------|--------------|------------
Body Exec   |              |              |
Average     | 623ms  561ms | 578ms  580ms | 571ms 568ms
St Dev      | 18ms   11ms  | 19ms   9ms   | 9ms   10ms

结论

首先,请务必注意,我的操作假设您的脚本位于文档的 &lt;head&gt;(而不是 &lt;body&gt; 的末尾)。关于为什么您可能会链接到 &lt;head&gt; 中的脚本而不是文档的结尾,存在各种争论,但这超出了此答案的范围。这完全是关于&lt;script&gt;s 是否应该在&lt;head&gt; 中位于&lt;link&gt;s 之前。

在现代 DESKTOP 浏览器中,似乎首先链接到 CSS 从不提供了性能提升。当 CSS 和脚本都被延迟时,将 CSS 放在脚本之后会给您带来微不足道的收益,但在 CSS 延迟时会给您带来很大的收益。 (由第一组结果中的last 列显示。)

鉴于最后链接到 CSS 似乎不会影响性能,但可以在某些情况下提供收益,您应该链接到外部样式表在链接到之后外部脚本仅在桌面浏览器上如果旧浏览器的性能不是问题。 继续阅读以了解移动情况。

为什么?

从历史上看,当浏览器遇到指向外部资源的&lt;script&gt; 标记时,浏览器会停止解析 HTML,检索脚本,执行它,然后继续解析 HTML。相反,如果浏览器遇到外部样式表的&lt;link&gt;,它会继续在获取 CSS 文件的同时(并行)解析 HTML。

因此,广泛重复的建议是将样式表放在首位——它们会先下载,而要下载的第一个脚本可以并行加载。

然而,现代浏览器(包括我上面测试过的所有浏览器)已经实现了speculative parsing,浏览器在 HTML 中“向前看”并开始下载资源脚本下载和执行之前.

在没有推测解析的旧浏览器中,将脚本放在首位会影响性能,因为它们不会并行下载。

浏览器支持

推测性解析首次实现于:(以及截至 2012 年 1 月使用此版本或更高版本的全球桌面浏览器用户的百分比)

  • Chrome 1 (WebKit 525) (100%)
  • IE 8 (75%)
  • Firefox 3.5 (96%)
  • Safari 4 (99%)
  • Opera 11.60 (85%)

总的来说,目前使用的桌面浏览器中大约有 85% 支持推测加载。将脚本放在 CSS 之前将对 15% 的用户全球造成性能损失; YMMV 基于您网站的特定受众。 (请记住,这个数字正在减少。)

在移动浏览器上,仅仅由于移动浏览器和操作系统环境的异构性,要获得确定的数字有点困难。由于推测性渲染是在 WebKit 525(2008 年 3 月发布)中实现的,并且几乎所有有价值的移动浏览器都基于 WebKit,我们可以得出结论,“大多数”移动浏览器应该支持它。根据quirksmode,iOS 2.2/Android 1.0 使用 WebKit 525。我不知道 Windows Phone 长什么样。

但是,我在我的 Android 4 设备上运行了测试,虽然我看到了与桌面结果相似的数字,但我将它连接到 Android 版 Chrome 中奇妙的新 remote debugger,并且网络选项卡显示浏览器实际上一直在等待下载 CSS,直到 JavaScript 完全加载——换句话说,即使是最新版本的 Android 版 WebKit 似乎也不支持推测解析。我怀疑它可能由于移动设备固有的 CPU、内存和/或网络限制而被关闭。

代码

原谅我的草率——这是问答。

app.js

var express = require('express')
, app = express.createServer()
, fs = require('fs');

app.listen(90);

var file={};
fs.readdirSync('.').forEach(function(f) {
    console.log(f)
    file[f] = fs.readFileSync(f);
    if (f != 'jquery.js' && f != 'style.css') app.get('/' + f, function(req,res) {
        res.contentType(f);
        res.send(file[f]);
    });
});


app.get('/jquery.js', function(req,res) {
    setTimeout(function() {
        res.contentType('text/javascript');
        res.send(file['jquery.js']);
    }, 500);
});

app.get('/style.css', function(req,res) {
    setTimeout(function() {
        res.contentType('text/css');
        res.send(file['style.css']);
    }, 500);
});


var headresults={
    css: [],
    js: []
}, bodyresults={
    css: [],
    js: []
}
app.post('/result/:type/:time/:exec', function(req,res) {
    headresults[req.params.type].push(parseInt(req.params.time, 10));
    bodyresults[req.params.type].push(parseInt(req.params.exec, 10));
    res.end();
});

app.get('/result/:type', function(req,res) {
    var o = '';
    headresults[req.params.type].forEach(function(i) {
        o+='\n' + i;
    });
    o+='\n';
    bodyresults[req.params.type].forEach(function(i) {
        o+='\n' + i;
    });
    res.send(o);
});

css.html

<!DOCTYPE html>
<html>
    <head>
        <title>CSS first</title>
        <script>var start = Date.now();</script>
        <link rel="stylesheet" href="style.css">
        <script src="jquery.js"></script>
        <script src="test.js"></script>
    </head>
    <body>
        <script>document.write(jsload - start);bodyexec=Date.now()</script>
    </body>
</html>

js.html

<!DOCTYPE html>
<html>
    <head>
        <title>CSS first</title>
        <script>var start = Date.now();</script>
        <script src="jquery.js"></script>
        <script src="test.js"></script>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <script>document.write(jsload - start);bodyexec=Date.now()</script>
    </body>
</html>

test.js

var jsload = Date.now();


$(function() {
    $.post('/result' + location.pathname.replace('.html','') + '/' + (jsload - start) + '/' + (bodyexec - start));
});

jquery.js 是 jquery-1.7.1.min.js

【讨论】:

  • 这是一个绝妙的答案,感谢using the science! 根据您的结果“在现代浏览器中,似乎首先链接到 CSS 永远不会提供性能提升”,我认为问题标题的答案是yes,CSS first 的旧建议显然是无效的。
  • 关于@josh3736 关于移动端逆向的更新......这是一个很好的例子,不要急于这一重大变化。我很好奇其他移动浏览器的行为方式(webkit、gecko、presto、trident 等),因为移动设备的性能通常更为重要。
  • 您还应该尝试在打印出 css/js 时添加一些慢速,以模拟慢速服务器的速度。
  • 如果使用 defer 或 async 怎么样?那会改变吗? (尝试使用内联脚本和不使用内联脚本)会改变吗?
  • "首先,重要的是要注意,我是在假设您的文档的 &lt;head&gt; 中有脚本(而不是 &lt;body&gt; 的末尾)的情况下进行操作的。 )。” 我会在答案的前面很多强调这一点,就像在顶部一样。在 head 中包含引用外部文件的 script 几乎从不正确,从几乎任何角度来看(当然不是性能角度)。我不记得在现实生活中必须这样做。 inline 脚本中可能有一两行奇数,但仅此而已。默认值,没有 非常 很好的相反原因,应该是正文的结尾。
【解决方案2】:

将 CSS 放在 JavaScript 之前有两个主要原因。

  1. 旧版浏览器(Internet Explorer 6-7、Firefox 2 等)在开始下载脚本时会阻止所有后续下载。因此,如果您有a.js,然后是b.css,它们将按顺序下载:首先是a,然后是b。如果您有b.css 后跟a.js,则它们会被并行下载,因此页面加载速度更快。

  2. 在下载所有样式表之前不会呈现任何内容 - 在所有浏览器中都是如此。脚本是不同的——它们会阻止页面中 位于脚本标签下的所有 DOM 元素的呈现。如果将脚本放在 HEAD 中,则意味着在下载所有样式表和所有脚本之前,整个页面将被阻止呈现。虽然阻止样式表的所有呈现是有意义的(因此您可以第一次获得正确的样式并避免无样式内容 FOUC 的闪烁),但阻止脚本呈现整个页面是没有意义的。通常脚本不会影响任何 DOM 元素或仅影响 DOM 元素的一部分。 最好将脚本加载到页面中尽可能低的位置,或者更好地异步加载它们。

Cuzillion 创建示例很有趣。例如,this page 在 HEAD 中有一个脚本,因此整个页面在下载完成之前都是空白的。但是,如果我们将脚本移动到 BODY 块的末尾,页面标题就会呈现,因为这些 DOM 元素出现在 SCRIPT 标记上方,正如您在 this page 上看到的那样。

【讨论】:

  • 尊敬的史蒂夫击败了我,但我会添加一篇与他提到的内容相关的文章:stevesouders.com/blog/2009/04/27/…
  • 查看哪些浏览器支持 async 属性,Steve 在这里推荐“更好地异步加载它们” -- stackoverflow.com/questions/1834077/…
  • 嘿,你能告诉我为什么有人会用 @import 指令链接 CSS 文件吗?
  • 2) 的来源是什么,如果是真的,你能解释一下为什么有时页面会完成加载内容,然后 CSS 会在一两秒后应用吗? (这种情况很少发生在我自己的页面上,其中 CSS 位于 标记中)
  • 所以我们应该把jQuery + jQuery UI + $(document).ready(function () { }); 放在页面末尾?它会始终按预期工作吗?
【解决方案3】:

我不会过分强调你得到的结果,我认为这是主观的,但我有理由向你解释,最好在 js 之前放入 CSS。

在加载您的网站期间,您会看到两种情况:

案例 1:白屏 > 无样式的网站 > 样式化的网站 > 交互 > 样式化和交互的网站

案例 2:白屏 > 无样式网站 > 交互 > 样式网站 > 样式和交互网站


老实说,我无法想象有人会选择案例 2。这意味着使用慢速互联网连接的访问​​者将面临一个无样式的网站,这允许他们使用 Javascript 与它进行交互(因为它已经加载)。此外,通过这种方式可以最大限度地增加查看无样式网站的时间。为什么会有人想要那个?

jQuery states 也更有效

"当使用依赖 CSS 样式属性值的脚本时, 引用外部样式表或嵌入样式很重要 引用脚本之前的元素”。

当文件以错误的顺序加载时(首先是 JS,然后是 CSS),任何依赖于 CSS 文件中设置的属性(例如 div 的宽度或高度)的 Javascript 代码都将无法正确加载。似乎在加载顺序错误的情况下,Javascript 有时会知道正确的属性(也许这是由竞争条件引起的?)。根据所使用的浏览器,此效果似乎更大或更小。

【讨论】:

  • 您将如何保证在 ja​​vascript 执行之前加载所有 css?你可以吗?或者您的 javascript 是否足够健壮以处理可能不一定会加载样式的情况。
  • @Jonnio 如果您的 JS 有依赖项,那么您应该明确该依赖项。否则,您将始终遇到罕见的时间问题。 ES6 模块是实现这一目标的好方法,但也有许多库可以使用。
【解决方案4】:

您的测试是在您的个人计算机上还是在网络服务器上进行的?它是一个空白页面,还是一个包含图像、数据库等的复杂在线系统?您的脚本是执行简单的悬停事件操作,还是您的网站如何呈现和与用户交互的核心组件?这里有几件事需要考虑,当您冒险进行高质量的 Web 开发时,这些建议的相关性几乎总是成为规则。

“将样式表放在顶部,脚本放在底部”规则的目的是,一般来说,这是实现最佳渐进式渲染的最佳方式,这对用户体验至关重要。

除此之外:假设您的测试是有效的,并且您确实产生了与流行规则相反的结果,这并不奇怪,真的。每个网站(以及使整个内容出现在用户屏幕上所需的一切)都是不同的,互联网也在不断发展。

【讨论】:

  • 我很欣赏你用粗体提出的观点,但 OP 正在谈论当你改变顺序时会发生什么,both 在顶部,而不是在底部。
  • 因此,“假设 [his] 测试有效。”
【解决方案5】:

出于不同的原因,我在 Javascript 之前包含 CSS 文件。

如果我的 Javascript 需要对某些页面元素进行动态调整大小(对于那些 CSS 确实是后面主要内容的极端情况),那么在 JS russing 之后加载 CSS 可能会导致竞争条件,其中元素被调整大小在应用 CSS 样式之前,因此当样式最终启动时看起来很奇怪。如果我预先加载 CSS,我可以保证事情按预期的顺序运行,并且最终的布局是我想要的。

【讨论】:

  • 这将在某些浏览器上中断一天。我没猜。
  • jcolebrand:是的,我想我在写这篇文章时还没有喝足够的咖啡。 (回想起来,我想重要的事情只是避免动态加载 CSS 并将 JS 放入 domReady 事件中,如果您需要进行动态调整)
  • 脚本不应改变任何显示。这就是 CSS 的工作。 HTML = 内容,CSS = 如何显示内容,javascript 动态更改内容。此外,js 应该只在 DOMContentLoaded 被触发之后(或同时)在一些很少但非常具体的情况下采取行动。
  • @brunoais:有些布局只能使用 Javascript 创建。例如,任何需要动态调整大小的东西都必须通过 Javascript 进行,有些事情(比如大小为 100% - 20px)需要 Javascript 在旧浏览器中以可移植的方式完成。
  • @missingno 在这些情况下,无论如何,只需使用 DOMContentLoaded 事件。但我明白你的意思。 (愚蠢的 IE!)
【解决方案6】:

在 JavaScript 之前包含 CSS 的建议是否无效?

如果您仅将其视为建议,则不会。但是,如果您将其视为硬性规定?是的,它是无效的。

来自https://developer.mozilla.org/en-US/docs/Web/Reference/Events/DOMContentLoaded

样式表加载块脚本执行,所以如果你有一个&lt;script&gt;&lt;link rel="stylesheet" ...&gt; 之后页面将无法完成解析 - 并且 DOMContentLoaded 不会触发 - 直到样式表被加载。

看来您需要知道每个脚本所依赖的内容,并确保脚本的执行延迟到正确的完成事件之后。如果脚本仅依赖于 DOM,它可以在 ondomready/domcontentloaded 中恢复,如果它依赖于要加载的图像或要应用的样式表,那么如果我正确阅读了上述参考,则该代码必须推迟到 onload 事件。

我不认为一种袜子尺码适合所有人,尽管这是他们的销售方式,而且我知道一种鞋码并不适合所有人。我不认为首先加载样式或脚本有明确的答案。更多的是逐案决定什么必须以什么顺序加载,什么可以推迟到以后,因为不在“关键路径”上。

与评论说最好延迟用户交互能力直到工作表漂亮的观察者交谈。有很多人在那里,你惹恼了那些感觉相反的同行。他们来到一个站点是为了完成一个目的,而在等待无关紧要的事情完成加载的同时延迟与站点交互的能力非常令人沮丧。我并不是说你错了,只是你应该意识到存在另一个派别与你的优先级不同。

这个问题尤其适用于所有放置在网站上的广告。如果网站作者只为广告内容呈现占位符 div 并确保他们的网站在加载事件中注入广告之前已加载并具有交互性,我会很高兴。即使这样,我也希望看到广告是连续加载的,而不是一次全部加载,因为它们会影响我在加载臃肿的广告时甚至滚动网站内容的能力。但这只是一个人的观点。

  • 了解您的用户以及他们的价值。
  • 了解您的用户以及他们使用的浏览环境。
  • 了解每个文件的作用及其先决条件。让一切正常运行将优先于速度和美观。
  • 在开发时使用可显示网络时间线的工具。
  • 在您的用户使用的每个环境中进行测试。可能需要根据用户环境动态​​地(服务器端,在创建页面时)更改加载顺序。
  • 如有疑问,请更改顺序并重新测量。
  • 在加载顺序中混合样式和脚本可能是最佳的;不是所有一个,然后是另一个。
  • 不仅要试验加载文件的顺序,还要试验加载位置。头?在身体?身体之后? DOM 准备好/加载了吗?加载了吗?
  • 在适当的时候考虑异步和延迟选项,以减少用户在能够与页面交互之前体验到的网络延迟。测试以确定它们是帮助还是伤害。
  • 在评估最佳加载顺序时总是需要权衡取舍。漂亮与响应只是其中之一。

【讨论】:

  • 链接的文章不再声称“样式表加载块脚本执行”。这不再是真的吗?
  • @Greg - 这仍然是真的。脚本需要能够查询 DOM .style 属性,因此样式表仍然会阻止脚本执行。如果他们很聪明,他们可能不会阻止脚本加载,但他们会阻止 script.onLoad 事件。
【解决方案7】:

2017 年 12 月 16 日更新

我不确定 OP 中的测试。我决定尝试一下,最终打破了一些神话。

同步&lt;script src...&gt; 将阻止下载资源 在它下面直到它被下载并执行

这不再是事实。看看 Chrome 63 生成的瀑布:

<head>
<script src="//alias-0.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=1"></script>
<script src="//alias-1.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=2"></script>
<script src="//alias-2.redacted.com/payload.php?type=js&amp;delay=333&amp;rand=3"></script>
</head>

&lt;link rel=stylesheet&gt; 不会阻止下载和执行 下面的脚本

这是不正确的。样式表不会阻止下载,但它阻止脚本的执行 (little explanation here)。看看 Chrome 63 生成的性能图表:

<link href="//alias-0.redacted.com/payload.php?type=css&amp;delay=666" rel="stylesheet">
<script src="//alias-1.redacted.com/payload.php?type=js&amp;delay=333&amp;block=1000"></script>


记住以上,OP中的结果可以解释如下:

CSS 优先:

CSS Download  500ms:<------------------------------------------------>
JS Download   400ms:<-------------------------------------->
JS Execution 1000ms:                                                  <-------------------------------------------------------------------------------------------------->
DOM Ready   @1500ms:                                                                                                                                                      ◆

JS 优先:

JS Download   400ms:<-------------------------------------->
CSS Download  500ms:<------------------------------------------------>
JS Execution 1000ms:                                        <-------------------------------------------------------------------------------------------------->
DOM Ready   @1400ms:                                                                                                                                            ◆

【讨论】:

  • 这也是为什么 document.write() 是 HTMLDOM 有史以来最糟糕的想法之一。
  • The reason is that the script may want to get coordinates and other style-dependent properties of elements, like in the example above. Naturally, it has to wait for styles to load. javascript.info/… 为什么同样的假设不适用于 JS 首先?对我来说没有多大意义,执行 JS 的顺序并不能说明它的目的。
【解决方案8】:

我不确定您的测试如何“渲染”时间,因为您使用的是 java 脚本。但是考虑一下这个

您网站上的一页是 50k,这并非不合理。用户在东海岸,而您的服务器在西海岸。 MTU绝对不是10k,所以来回会有几次。接收您的页面和样式表可能需要 1/2 秒。通常(对我而言)javascript(通过 jquery 插件等)远不止 CSS。当您的互联网连接在页面中途阻塞时也会发生什么,但让我们忽略它(我偶尔会发生这种情况,我相信 css 呈现,但我不是 100% 确定)。

由于 css 在 head 中,可能会有额外的连接来获取它,这意味着它可能会在页面完成之前完成。无论如何,在页面其余部分采用的类型和 javascript 文件(更多字节)期间,页面没有样式,这使得站点/连接看起来很慢。

即使 JS 解释器在 CSS 完成之前拒绝启动,下载 javascript 代码所花费的时间尤其是当远离服务器时正在缩短 css 时间,这会使网站看起来不漂亮。

这是一个小的优化,但这就是它的原因。

【讨论】:

  • 服务器在东海岸,fwiw。显然,您也不知道他们现在使用 CDN。
【解决方案9】:

这是上面所有主要答案的摘要(或者稍后可能会在下面:)

对于现代浏览器,将 css 放在您喜欢的任何位置。他们会分析您的 html 文件(他们称之为 推测性解析)并开始与 html 解析并行下载 css。

对于旧浏览器,请继续将 css 放在首位(如果您不想先显示一个裸露但可交互的页面)。

对于所有浏览器,将 javascript 放在页面上尽可能靠后的位置,因为它会停止解析您的 html。最好异步下载(即ajax调用)

还有一些针对特定案例的实验结果,声称将 javascript 放在首位(与将 CSS 放在首位的传统智慧相反)可以提供更好的性能,但没有给出逻辑推理,并且缺乏关于广泛适用性的验证,所以你现在可以忽略它。

所以,回答这个问题:是的。在 JS 之前包含 CSS 的建议对于现代浏览器是无效的。把 CSS 放在你喜欢的地方,把 JS 放在最后。

【讨论】:

  • 将javascript脚本放置在head标签甚至CSS之前的一个用例是处理浏览器无法提前知道的样式,例如最近的暗/亮模式趋势网络应用程序。它应该是一个小脚本,仅用于读取会话,然后根据用户会话设置样式(css 变量或其他方式)。这可以防止在脚本切换到设置样式之前呈现默认样式。
【解决方案10】:

2020 年的答案:可能没关系

这里的最佳答案来自 2012 年,所以我决定自己测试一下。在 Android 版 Chrome 上,JS 和 CSS 资源是并行下载的,我无法检测到页面渲染速度的差异。

我在博客中添加了more detailed writeup

【讨论】:

    【解决方案11】:

    Steve Souders 已经给出了明确的答案,但是......

    我想知道 Sam 的原始测试和 Josh 的重复测试是否存在问题。

    这两项测试似乎都是在低延迟连接上执行的,而设置 TCP 连接的成本很小。

    这对测试结果有何影响我不确定,我想通过“正常”延迟连接查看测试的瀑布,但是...

    下载的第一个文件应该获得用于 html 页面的连接,下载的第二个文件将获得新的连接。 (冲洗早期会改变这种动态,但这里没有这样做)

    在较新的浏览器中,第二个 TCP 连接是推测性地打开的,因此连接开销会减少/消失,但在较旧的浏览器中,情况并非如此,并且第二个连接将具有打开的开销。

    我不确定这如何/是否会影响测试结果。

    【讨论】:

    • 不跟随,除非你有非常罕见的流水线,否则你不太可能减少连接设置......同意测试应该以低延迟重复
    • 如果你看一下这个瀑布,你可以看到 Chrome 在需要它之前推测性地打开了第二个连接webpagetest.org/result/…(IE9 也是如此)......我认为 TCP 目的的正常延迟而不是低 - 测试是在什么样的环境中进行的?
    • 回复:“Steve Souders 已经给出了明确的答案,但是......” 网络进化的问题是没有明确的答案。 :) 有 3-4 种加载脚本的方法,事情会发生变化。实际正确的语义实际上应该是 Steve 说“将 CSS 放在同步 JavaScript 之前”,否则人们会因为它是所有脚本的规则而将其概括为错误...
    • 是的,但大多数人只是同步包含脚本,所以史蒂夫的建议对初学者来说是好的。
    【解决方案12】:

    我认为这不适用于所有情况。因为 css 会并行下载而 js 不能。考虑相同的情况,

    不要使用单个 css,而是使用 2 或 3 个 css 文件并尝试这些方法,

    1) css..css..js 2) css..js..css 3) js..css..css

    我确信 css..css..js 会提供比其他所有更好的结果。

    【讨论】:

      【解决方案13】:

      我们必须记住,新的浏览器已经在他们的 Javascript 引擎、解析器等方面工作,以一种在

      【讨论】:

      • 性能始终是个问题。我几乎忽略了不遵循规范的浏览器的存在。我只是准备我的代码,以便遵循规范的代码可以全速工作,而其他代码我只是这样做才能正常工作。因此,例如,如果它只在 IE8 中工作,一切正常。
      【解决方案14】:

      就个人而言,我不会过分强调这种“民间智慧”。过去可能是真的,现在可能不是真的。我会假设与网页的解释和呈现相关的所有操作都是完全异步的(“获取”某些东西和“对其采取行动”是两个完全不同的事情,可能由不同的线程处理,等等。 ),并且在任何情况下都完全超出您的控制或关注范围。

      我会将 CSS 引用以及对外部脚本的任何引用放在文档的“头部”部分。 (有些脚本可能会要求放在正文中,如果是,请强制执行。)

      除此之外...如果您观察到“在这个/那个浏览器上,这似乎比那个更快/更慢”,将此观察结果视为有趣但无关的好奇心,不要让它影响你的设计决策。太多东西变化太快。 (任何人都想打赌在 Firefox 团队推出他们产品的另一个临时版本之前需要多少 分钟?是的,我也没有。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-22
        • 1970-01-01
        • 2010-11-28
        • 2015-07-12
        • 1970-01-01
        • 2014-08-10
        相关资源
        最近更新 更多