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." (我总是把我的CSS <link href="...">
放在我的JS <script src="...">
s之前,因为“我读过一次它更好。”)
So, you're right; (所以,你是对的;)
it's high time we do some actual research! (现在是我们做一些实际研究的时候了!)
I set up my own test harness in Node (code below).
(我在Node中设置了自己的测试工具(下面的代码)。)
Basically, I: (基本上,我:)
- Made sure there was no HTTP caching so the browser would have to do a full download each time a page is loaded.
(确保没有HTTP缓存,因此每次加载页面时浏览器都必须进行完整下载。)
- To simulate reality, I included jQuery and the H5BP CSS (so there's a decent amount of script/CSS to parse)
(为了模拟现实,我包含了jQuery和H5BP CSS(所以要解析相当数量的脚本/ CSS))
- Set up two pages - one with CSS before script, one with CSS after script.
(设置两个页面 - 一个在脚本之前使用CSS,一个在脚本之后使用CSS。)
- Recorded how long it took for the external script in the
<head>
to execute (记录<head>
的外部脚本执行所花费的时间)
- Recorded how long it took for the inline script in the
<body>
to execute, which is analogous to DOMReady
. (记录<body>
的内联脚本执行所花费的时间,类似于DOMReady
。)
- Delayed sending CSS and/or script to the browser by 500ms.
(延迟将500和/或脚本发送到浏览器500ms。)
- Ran the test 20 times in the 3 major browsers.
(在3个主要浏览器中进行了20次测试。)
Results (结果)
First, with the CSS file delayed by 500ms:
(首先,CSS文件延迟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
Next, I set jQuery to delay by 500ms instead of the CSS:
(接下来,我将jQuery设置为延迟500ms而不是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
Finally, I set both jQuery and the CSS to delay by 500ms:
(最后,我都设置jQuery和CSS的由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
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>
).
(首先,重要的是要注意我在假设您的脚本位于文档的<head>
(而不是<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. (关于为什么你可以链接到<head>
和文档末尾的脚本有各种各样的争论,但这超出了这个答案的范围。)
This is strictly about whether <script>
s should go before <link>
s in the <head>
. (这严格关于<script>
是否应该在<head>
中的<head>
<link>
之前。)
In modern DESKTOP browsers, it looks like linking to CSS first never provides a performance gain.
(在现代DESKTOP浏览器中,看起来像链接到CSS首先永远不会提供性能增益。)
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. (当CSS和脚本被延迟时,在脚本之后放置CSS可以获得微不足道的收益,但是当CSS延迟时会给你带来很大的收益。)
(Shown by the last
columns in the first set of results.) ((由第一组结果中的last
列显示。))
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.
(鉴于最后链接到CSS并不会损害性能但在某些情况下可以提供增益,如果不考虑旧浏览器的性能,则应在仅在桌面浏览器上链接到外部脚本后链接到外部样式表 。)
Read on for the mobile situation. (继续阅读移动情况。)
Why? (为什么?)
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.
(从历史上看,当浏览器遇到指向外部资源的<script>
标记时,浏览器将停止解析HTML,检索脚本,执行它,然后继续解析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). (相反,如果浏览器遇到外部样式表的<link>
,它将在获取CSS文件(并行)时继续解析HTML。)
Hence, the widely-repeated advice to put stylesheets first – they would download first, and the first script to download could be loaded in parallel.
(因此,广泛重复的建议首先放置样式表 - 他们将首先下载,并且可以并行加载下载的第一个脚本。)
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.
(但是,现代浏览器(包括我上面测试过的所有浏览器)都实现了推测性解析 ,其中浏览器在HTML中“向前看”,并在脚本下载和执行之前开始下载资源。)
In old browsers without speculative parsing, putting scripts first will affect performance since they will not download in parallel.
(在没有推测性解析的旧浏览器中,首先放置脚本会影响性能,因为它们不会并行下载。)
Browser Support (浏览器支持)
Speculative parsing was first implemented in: (along with the percentage of worldwide desktop browser users using this version or greater as of Jan 2012)
(推测性解析首先在以下方面实施:(以及截至2012年1月使用此版本或更高版本的全球桌面浏览器用户的百分比))
In total, roughly 85% of desktop browsers in use today support speculative loading.
(总的来说,目前使用的大约85%的桌面浏览器支持投机加载。)
Putting scripts before CSS will have a performance penalty on 15% of users globally ; (在CSS之前放置脚本将对全球 15%的用户造成性能损失;)
YMMV based on your site's specific audience. (YMMV基于您网站的特定受众群体。)
(And remember that number is shrinking.) ((并记住这个数字在缩小。))
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. (由于推测性渲染是在WebKit 525(2008年3月发布)中实现的,几乎所有有价值的移动浏览器都基于WebKit,我们可以得出结论,“大多数”移动浏览器应该支持它。)
According to quirksmode , iOS 2.2/Android 1.0 use WebKit 525. I have no idea what Windows Phone looks like. (根据quirksmode ,iOS 2.2 / Android 1.0使用WebKit 525.我不知道Windows Phone是什么样的。)
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.
(但是,我在我的Android 4设备上运行测试,虽然我看到类似于桌面结果的数字,但我将它连接到Chrome for Android中的神奇新远程调试器,而Network选项卡显示浏览器实际上正在等待下载CSS直到JavaScripts完全加载 - 换句话说, 即使是最新版本的WebKit for Android似乎也不支持推测性解析。)
I suspect it might be turned off due to the CPU, memory, and/or network constraints inherent to mobile devices. (我怀疑它可能因移动设备固有的CPU,内存和/或网络限制而被关闭。)
Code (码)
Forgive the sloppiness – this was Q&D.
(原谅这种邋 - - 这就是Q&D。)
app.js
(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(funct