Đây là một câu hỏi rất thú vị. Tôi đã luôn đặt CSS <link href="...">
của mình trước mã JS <script src="...">
của mình vì "Tôi đã đọc một lần rằng nó tốt hơn." Vì vậy, bạn đã đúng; đã đến lúc chúng ta thực hiện một số nghiên cứu thực tế!
Tôi thiết lập khai thác thử nghiệm của riêng tôi trong Node (mã bên dưới). Về cơ bản, tôi:
- Đảm bảo không có bộ đệm HTTP để trình duyệt phải tải xuống đầy đủ mỗi khi trang được tải.
- Để mô phỏng thực tế, tôi đã bao gồm jQuery và H5BP CSS (vì vậy có một lượng kịch bản / CSS kha khá để phân tích)
- Thiết lập hai trang - một trang có CSS trước tập lệnh, một trang có CSS sau tập lệnh.
- Ghi lại mất bao lâu cho tập lệnh bên ngoài
<head>
để thực thi
- Ghi lại thời gian cần thiết cho tập lệnh nội tuyến
<body>
để thực thi, tương tự như vậy DOMReady
.
- Trì hoãn gửi CSS và / hoặc tập lệnh tới trình duyệt 500ms.
- Chạy thử 20 lần trong 3 trình duyệt chính.
Các kết quả
Đầu tiên, với tệp CSS bị trễ 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
Tiếp theo, tôi đặt jQuery để trì hoãn 500ms thay vì 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
Cuối cùng, tôi đặt cả jQuery và CSS để trì hoãn 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
Kết luận
Đầu tiên, điều quan trọng cần lưu ý là tôi đang hoạt động theo giả định rằng bạn có các tập lệnh nằm trong <head>
tài liệu của bạn (trái ngược với phần cuối của tài liệu <body>
). Có nhiều tranh luận liên quan đến lý do tại sao bạn có thể liên kết đến các tập lệnh của mình ở <head>
phần cuối của tài liệu, nhưng điều đó nằm ngoài phạm vi của câu trả lời này. Đây là nghiêm túc về việc <script>
s nên đi trước <link>
s trong <head>
.
Trong các trình duyệt DESKTOP hiện đại, có vẻ như liên kết với CSS trước tiên không bao giờ cung cấp hiệu suất. Đặt CSS sau tập lệnh sẽ mang lại cho bạn một mức tăng không đáng kể khi cả CSS và tập lệnh bị trì hoãn, nhưng mang lại cho bạn mức tăng lớn khi CSS bị trì hoãn. (Được hiển thị bởi các last
cột trong tập kết quả đầu tiên.)
Vì liên kết đến CSS lần cuối dường như không ảnh hưởng đến hiệu suất nhưng có thể mang lại lợi ích trong một số trường hợp nhất định, bạn nên liên kết với các bảng định kiểu bên ngoài sau khi bạn chỉ liên kết với các tập lệnh bên ngoài trên trình duyệt máy tính để bàn nếu hiệu suất của trình duyệt cũ không phải là vấn đề đáng lo ngại. Đọc về tình hình di động.
Tại sao?
Trước đây, khi một trình duyệt gặp phải một <script>
thẻ trỏ đến một tài nguyên bên ngoài, trình duyệt sẽ dừng phân tích cú pháp HTML, truy xuất tập lệnh, thực thi nó, sau đó tiếp tục phân tích cú pháp HTML. Ngược lại, nếu trình duyệt gặp phải một biểu <link>
định kiểu bên ngoài, nó sẽ tiếp tục phân tích cú pháp HTML trong khi nó tìm nạp tệp CSS (song song).
Do đó, lời khuyên được lặp đi lặp lại rộng rãi để đặt biểu định kiểu lên hàng đầu - chúng sẽ tải xuống trước và tập lệnh đầu tiên để tải xuống có thể được tải song song.
Tuy nhiên, các trình duyệt hiện đại (bao gồm tất cả các trình duyệt tôi đã thử nghiệm ở trên) đã triển khai phân tích cú pháp đầu cơ , trong đó trình duyệt "nhìn về phía trước" trong HTML và bắt đầu tải xuống tài nguyên trước khi tập lệnh tải xuống và thực thi.
Trong các trình duyệt cũ không có phân tích cú pháp đầu cơ, việc đặt tập lệnh lên trước sẽ ảnh hưởng đến hiệu suất do chúng sẽ không tải xuống song song.
Hỗ trợ trình duyệt
Phân tích cú pháp đầu cơ được triển khai lần đầu tiên trong: (cùng với tỷ lệ người dùng trình duyệt máy tính để bàn trên toàn thế giới sử dụng phiên bản này hoặc cao hơn kể từ tháng 1 năm 2012)
- Chrome 1 (WebKit 525) (100%)
- IE 8 (75%)
- Firefox 3.5 (96%)
- Safari 4 (99%)
- Opera 11,60 (85%)
Tổng cộng, khoảng 85% trình duyệt máy tính để bàn đang sử dụng hiện nay hỗ trợ tải đầu cơ. Đặt các tập lệnh trước CSS sẽ có hiệu suất phạt đối với 15% người dùng trên toàn cầu ; YMMV dựa trên đối tượng cụ thể của trang web của bạn. (Và hãy nhớ rằng con số đó đang bị thu hẹp.)
Trên các trình duyệt di động, khó hơn một chút để có được các số chính xác chỉ đơn giản là do trình duyệt di động và bối cảnh hệ điều hành không đồng nhất như thế nào. Do kết xuất đầu cơ được triển khai trong WebKit 525 (phát hành tháng 3 năm 2008) và gần như mọi trình duyệt di động đáng giá đều dựa trên WebKit, chúng tôi có thể kết luận rằng "hầu hết" các trình duyệt di động nên hỗ trợ nó. Theo quirksmode , iOS 2.2 / Android 1.0 sử dụng WebKit 525. Tôi không biết Windows Phone trông như thế nào.
Tuy nhiên, tôi đã chạy thử nghiệm trên thiết bị Android 4 của mình và trong khi tôi thấy các con số tương tự với kết quả trên máy tính để bàn, tôi đã kết nối nó với trình gỡ lỗi từ xa mới tuyệt vời trong Chrome dành cho Android và tab Mạng cho thấy trình duyệt thực sự đang chờ để tải xuống CSS cho đến khi JavaScripts được tải hoàn toàn - nói cách khác, ngay cả phiên bản WebKit mới nhất cho Android cũng không xuất hiện để hỗ trợ phân tích cú pháp đầu cơ. Tôi nghi ngờ nó có thể bị tắt do CPU, bộ nhớ và / hoặc các ràng buộc mạng vốn có của thiết bị di động.
Mã
Tha thứ cho sự chậm chạp - đây là 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 là jquery-1.7.1.min.js