CSS是否应始终优先于Javascript? [英] Should CSS always preceed Javascript?

查看:55
本文介绍了CSS是否应始终优先于Javascript?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在网上的无数地方,我看到了建议在JavaScript之前加入CSS.推理通常是的这种形式:

In countless places online I have seen the recommendation to include CSS prior to JavaScript. The reasoning is generally, of this form:

在订购CSS和JavaScript时,您需要CSS 首先.原因是渲染线程具有所有 呈现页面所需的样式信息.如果是JavaScript 包括第一个,JavaScript引擎必须先解析所有内容 继续进行下一组资源.这意味着渲染 线程无法完全显示该页面,因为它没有所有 所需的样式.

When it comes to ordering your CSS and JavaScript, you want your CSS to come first. The reason is that the rendering thread has all the style information it needs to render the page. If the JavaScript includes come first, the JavaScript engine has to parse it all before continuing on to the next set of resources. This means the rendering thread can't completely show the page, since it doesn't have all the styles it needs.

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

My actual testing reveals something quite different:

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

I use the following Ruby script to generate specific delays for various resources:

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传输延迟.

The above mini server allows me to set arbitrary delays for JavaScript files (both server and client) and arbitrary CSS delays. For example, http://10.0.0.50:8081/test.css?delay=500 gives me a 500 ms delay transferring the CSS.

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

I use the following page to test.

<!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秒的时间来渲染:

When I include the CSS first, the page takes 1.5 seconds to render:

当我首先包含JavaScript时,页面需要1.4秒的时间来呈现:

When I include the JavaScript first, the page takes 1.4 seconds to render:

我在Chrome,Firefox和Internet Explorer中得到了类似的结果.但是,在Opera中,排序根本没有关系.

I get similar results in Chrome, Firefox and Internet Explorer. In Opera however, the ordering simply does not matter.

似乎正在发生的事情是JavaScript解释器拒绝启动,直到所有CSS被下载为止.因此,随着JavaScript线程获得更多的运行时间,似乎首先包含JavaScript会更有效.

What appears to be happening is that the JavaScript interpreter refuses to start until all the CSS is downloaded. So, it seems that having JavaScript includes first is more efficient as the JavaScript thread gets more run time.

我遗漏了一些东西吗,建议将CSS包含位置放在JavaScript包含位置之前是不正确的?

Am I missing something, is the recommendation to place CSS includes prior to JavaScript includes not correct?

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

推荐答案

这是一个非常有趣的问题.我总是将CSS <link href="...">放在我的JS <script src="...">之前,因为我读了一遍就更好了".所以,你是对的.现在该做一些实际的研究了!

This is a very interesting question. I've always put my CSS <link href="...">s before my JS <script src="...">s because "I read one time that it's better." So, you're right; it's high time we do some actual research!

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

I set up my own test harness in Node (code below). Basically, I:

  • 确保没有HTTP缓存,因此浏览器每次加载页面时都必须进行完整下载.
  • 为了模拟现实,我加入了jQuery和 H5BP CSS(因此,可以解析大量的脚本/CSS )
  • 设置两页-一页在脚本之前包含CSS,一页在脚本之后包含CSS.
  • <head> 中记录了外部脚本执行所需的时间
  • 记录了 <body> 中的内联脚本执行所需的时间,类似于DOMReady.
  • 将CSS和/或脚本发送到浏览器的时间延迟了500ms.
  • 在3种主要浏览器中进行20次测试.
  • Made sure there was no HTTP caching so the browser would have to do a full download each time a page is loaded.
  • To simulate reality, I included jQuery and the H5BP CSS (so there's a decent amount of script/CSS to parse)
  • Set up two pages - one with CSS before script, one with CSS after script.
  • Recorded how long it took for the external script in the <head> to execute
  • Recorded how long it took for the inline script in the <body> to execute, which is analogous to DOMReady.
  • Delayed sending CSS and/or script to the browser by 500ms.
  • Ran the test 20 times in the 3 major browsers.

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

First, with the CSS file delayed by 500ms:

     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:

Next, I set jQuery to delay by 500ms instead of the 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

最后,我将两者和jQuery都设置为延迟500毫秒:

Finally, I set both jQuery and the CSS to delay by 500ms:

     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

结论

首先,需要特别注意的是,我在假设您的文档位于文档<head>中(而不是<body>末尾)放置脚本的情况下进行操作.关于为什么您可能链接到<head>中的脚本而不是文档的末尾,存在各种争论,但这超出了此答案的范围.这完全是关于<script>是否应该在<head>中的<link>之前.

Conclusions

First, it's important to note that I'm operating under the assumption that you have scripts located in the <head> of your document (as opposed to the end of the <body>). There are various arguments regarding why you might link to your scripts in the <head> versus the end of the document, but that's outside the scope of this answer. This is strictly about whether <script>s should go before <link>s in the <head>.

在现代的DESKTOP浏览器中,似乎先从不链接到CSS可以提高性能.将CSS放在脚本之后可以在延迟CSS和脚本时获得微不足道的收益,但是在延迟CSS时可以带来很大的收益. (由第一组结果中的last列显示.)

In modern DESKTOP browsers, it looks like linking to CSS first never provides a performance gain. Putting CSS after script gets you a trivial amount of gain when both CSS and script are delayed, but gives you large gains when CSS is delayed. (Shown by the last columns in the first set of results.)

鉴于最后链接到CSS似乎并没有影响性能,但是 可以在某些情况下提供收益,您应该在链接到之后链接到外部样式表外部脚本仅在台式机浏览器上 (如果不考虑旧版浏览器的性能). 继续阅读有关移动的情况.

Given that linking to CSS last does not seem to hurt performance but can provide gains under certain circumstances, you should link to external stylesheets after you link to external scripts only on desktop browsers if the performance of old browsers is not a concern. Read on for the mobile situation.

从历史上看,当浏览器遇到指向外部资源的<script>标记时,浏览器将停止解析HTML,检索脚本,执行脚本,然后继续解析HTML.相反,如果浏览器遇到外部样式表的<link>,它将在提取CSS文件的同时继续解析HTML.

Historically, when a browser encountered a <script> tag pointing to an external resource, the browser would stop parsing the HTML, retrieve the script, execute it, then continue parsing the HTML. In contrast, if the browser encountered a <link> for an external stylesheet, it would continue parsing the HTML while it fetched the CSS file (in parallel).

因此,将样式表放在第一位的广泛建议–他们将首先下载,然后可以并行加载第一个要下载的脚本.

Hence, the widely-repeated advice to put stylesheets first – they would download first, and the first script to download could be loaded in parallel.

但是,现代的浏览器(包括我上面测试过的所有浏览器)已经实现了 推测性解析 ,其中浏览器在HTML中向前看",并在 脚本下载并执行之前开始下载资源.

However, modern browsers (including all of the browsers I tested with above) have implemented speculative parsing, where the browser "looks ahead" in the HTML and begins downloading resources before scripts download and execute.

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

In old browsers without speculative parsing, putting scripts first will affect performance since they will not download in parallel.

推测性解析首先在以下位置实现:(以及自2012年1月起,使用该版本或更高版本的全球桌面浏览器用户所占的百分比)

Speculative parsing was first implemented in: (along with the percentage of worldwide desktop browser users using this version or greater as of Jan 2012)

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

总共,目前使用的台式机浏览器中大约有85%支持推测性加载.将脚本放在CSS之前会对全球全局 15%的用户造成性能损失; YMMV根据您网站的特定受众群体. (请记住,这个数字正在减少.)

In total, roughly 85% of desktop browsers in use today support speculative loading. Putting scripts before CSS will have a performance penalty on 15% of users globally; YMMV based on your site's specific audience. (And remember that number is shrinking.)

在移动浏览器上,仅由于移动浏览器和OS的异构程度不同,很难获得确切的数字.由于投机渲染已在WebKit 525(2008年3月发布)中实现,并且几乎所有有价值的移动浏览器都基于WebKit,因此我们可以得出结论,大多数"移动浏览器应该支持它.根据 quirksmode ,iOS 2.2/Android 1.0使用WebKit525.我不知道Windows Phone的外观喜欢.

On mobile browsers, it's a little harder to get definitive numbers simply due to how heterogeneous the mobile browser and OS landscape is. Since speculative rendering was implemented in WebKit 525 (released Mar 2008), and just about every worthwhile mobile browser is based on WebKit, we can conclude that "most" mobile browsers should support it. According to quirksmode, iOS 2.2/Android 1.0 use WebKit 525. I have no idea what Windows Phone looks like.

但是,我在Android 4设备上进行了测试,尽管看到的数字与台式机结果相似,但仍将其连接到了奇妙的新 Android的最新版本的WebKit似乎也不支持推测性解析.我怀疑由于移动设备固有的CPU,内存和/或网络限制,它可能已关闭

However, I ran the test on my Android 4 device, and while I saw numbers similar to the desktop results, I hooked it up to the fantastic new remote debugger in Chrome for Android, and Network tab showed that the browser was actually waiting to download the CSS until the JavaScripts completely loaded – in other words, even the newest version of WebKit for Android does not appear to support speculative parsing. I suspect it might be turned off due to the CPU, memory, and/or network constraints inherent to mobile devices.

原谅草率–这是Q& D.

Forgive the sloppiness – this was Q&D.

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

jquery.js was jquery-1.7.1.min.js

这篇关于CSS是否应始终优先于Javascript?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆