在网上无数的地方,我都看到过在JavaScript之前使用CSS的建议。推理一般是这样的:

当涉及到CSS和JavaScript的排序时,你需要你的CSS 先来。原因是呈现线程拥有所有的 样式显示页面所需的信息。如果JavaScript include首先出现,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和ie浏览器上得到了类似的结果。然而,在Opera中,顺序并不重要。

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

我遗漏了什么吗?把CSS include放在JavaScript include之前的建议是不正确的吗?

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


当前回答

我们必须记住,新的浏览器已经在它们的JavaScript引擎、解析器等方面进行了优化,优化了常见的代码和标记问题,而在Internet Explorer 8或之前的老式浏览器中遇到的问题已经不再相关,不仅涉及标记,还涉及JavaScript变量、元素选择器等的使用。

我可以预见在不久的将来,技术发展到一定程度,性能就不再是问题了。

其他回答

我们必须记住,新的浏览器已经在它们的JavaScript引擎、解析器等方面进行了优化,优化了常见的代码和标记问题,而在Internet Explorer 8或之前的老式浏览器中遇到的问题已经不再相关,不仅涉及标记,还涉及JavaScript变量、元素选择器等的使用。

我可以预见在不久的将来,技术发展到一定程度,性能就不再是问题了。

史蒂夫·苏德斯已经给出了明确的答案,但是……

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

这两个测试似乎都是在低延迟连接上执行的,其中建立TCP连接的开销很小。

我不确定这会如何影响测试结果,我想在“正常”延迟连接上查看测试的瀑布,但是……

下载的第一个文件将获得用于HTML页面的连接,下载的第二个文件将获得新的连接。(提前刷新<head>会改变动态,但这里没有这样做。)

在较新的浏览器中,第二个TCP连接是投机性地打开的,因此连接开销减少/消失了。在旧的浏览器中,这是不正确的,并且第二个连接将有被打开的开销。

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

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

如果我的JavaScript代码需要做一些页面元素的动态大小(对于那些角落的情况下,CSS是真正的主要在后面),然后在JS是russing后加载CSS可能会导致竞争条件,其中元素是在CSS样式应用之前调整大小,因此,当样式最终启动时看起来很奇怪。如果我提前加载CSS,我可以保证事情按照预期的顺序运行,最终的布局是我想要的。

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

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

撇开其他因素不谈:假设您的测试是有效的,并且您的测试结果确实与流行规则相反,这并不令人惊讶,真的。每个网站(以及让整个网站出现在用户屏幕上的所有内容)都是不同的,互联网也在不断发展。

更新2017-12-16

我不确定op的测试。我决定做一点实验,最终打破了一些神话。

同步<脚本src…>将阻止资源的下载 直到下载并执行为止

这已经不是事实了。看看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>

样式表>将不会阻止下载和执行 下面的脚本

这是不正确的。样式表不会阻止下载,但会阻止脚本的执行(这里有一点解释)。看看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  500 ms:<------------------------------------------------>
JS Download   400 ms:<-------------------------------------->
JS Execution 1000 ms:                                                  <-------------------------------------------------------------------------------------------------->
DOM Ready   @1500 ms:                                                                                                                                                      ◆

JavaScript:

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