Haruskah CSS selalu mendahului Javascript?

897

Di banyak tempat online saya telah melihat rekomendasi untuk memasukkan CSS sebelum JavaScript. Alasannya secara umum, dari bentuk ini :

Ketika datang untuk memesan CSS dan JavaScript Anda, Anda ingin CSS Anda yang lebih dulu. Alasannya adalah bahwa thread rendering memiliki semua informasi gaya yang diperlukan untuk membuat halaman. Jika JavaScript termasuk yang diutamakan, mesin JavaScript harus menguraikan semuanya sebelum melanjutkan ke rangkaian sumber daya berikutnya. Ini berarti untaian rendering tidak dapat sepenuhnya menampilkan halaman, karena tidak memiliki semua gaya yang dibutuhkan.

Pengujian saya yang sebenarnya mengungkapkan sesuatu yang sangat berbeda:

Uji harness saya

Saya menggunakan skrip Ruby berikut untuk menghasilkan penundaan spesifik untuk berbagai sumber daya:

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..."
}

Server mini di atas memungkinkan saya untuk mengatur penundaan sewenang-wenang untuk file JavaScript (baik server dan klien) dan penundaan CSS sewenang-wenang. Misalnya, http://10.0.0.50:8081/test.css?delay=500beri saya penundaan 500 ms saat mentransfer CSS.

Saya menggunakan halaman berikut untuk menguji.

<!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>

Ketika saya memasukkan CSS terlebih dahulu, halaman membutuhkan 1,5 detik untuk merender:

CSS dulu

Ketika saya memasukkan JavaScript terlebih dahulu, halaman membutuhkan 1,4 detik untuk merender:

JavaScript terlebih dahulu

Saya mendapatkan hasil yang serupa di Chrome, Firefox dan Internet Explorer. Namun di Opera, pemesanan tidak masalah.

Apa yang tampaknya terjadi adalah bahwa penerjemah JavaScript menolak untuk memulai sampai semua CSS diunduh. Jadi, tampaknya memiliki JavaScript yang disertakan terlebih dahulu lebih efisien karena utas JavaScript semakin lama berjalan.

Apakah saya kehilangan sesuatu, apakah rekomendasi untuk memasukkan CSS sebelum JavaScript termasuk tidak benar?

Jelas bahwa kita dapat menambahkan async atau menggunakan setTimeout untuk membebaskan utas render atau meletakkan kode JavaScript di footer, atau menggunakan loader JavaScript. Intinya di sini adalah tentang pemesanan bit JavaScript penting dan bit CSS di kepala.

Sam Saffron
sumber
120
adalah 1511 vs 1422 perbedaan yang signifikan secara statistik? Itu 6 persen. Ambang umum untuk perbedaan kinerja manusia yang terkenal rata-rata adalah sekitar 20 persen.
Jeff Atwood
15
intinya adalah bahwa pemesanan ulang menghilangkan penundaan sewenang-wenang ini, Anda dapat mengatur penundaan untuk apa pun yang Anda inginkan, itu hanya demo masalah.
Sam Saffron
3
apakah keterlambatan Anda 100 ms? perbedaan dalam tangkapan layar Anda adalah 89 ms. Di URL Anda itu delay=400&amp;jsdelay=1000dan delay=500yang mana dekat 100ms atau 89ms. Saya kira saya tidak jelas nomor mana yang Anda maksud.
Jeff Atwood
4
"Jika Javascript termasuk yang diutamakan, mesin Javascript harus menguraikan semuanya sebelum melanjutkan ke set sumber daya berikutnya. Ini berarti untaian rendering tidak dapat sepenuhnya menampilkan halaman, karena tidak memiliki semua gaya yang dibutuhkan . " - jika JS include ada di kepala maka JS akan dieksekusi sebelum halaman diberikan terlepas dari apakah CSS termasuk sebelum atau sesudah.
nnnnnn
162
Tidak yakin apakah Anda sudah mempertimbangkan hal ini, tetapi persepsi waktu buka juga penting. Jadi, misalnya, jika memuat CSS pertama memberi Anda bahkan hanya warna latar belakang / tekstur halaman, tampaknya akan lebih cepat. Waktu muat absolut mungkin tidak mengindikasikan hal ini.
Rakesh Pai

Jawaban:

712

Ini pertanyaan yang sangat menarik. Saya selalu meletakkan CSS saya <link href="...">sebelum JS saya <script src="...">karena "Saya pernah membaca bahwa itu lebih baik." Jadi kamu benar; sudah saatnya kita melakukan penelitian yang sebenarnya!

Saya mengatur test harness saya sendiri di Node (kode di bawah). Pada dasarnya, saya:

  • Pastikan tidak ada caching HTTP sehingga browser harus melakukan unduhan penuh setiap kali halaman dimuat.
  • Untuk mensimulasikan kenyataan, saya memasukkan jQuery dan H5BP CSS (jadi ada sejumlah script / CSS yang layak untuk diurai)
  • Siapkan dua halaman - satu dengan CSS sebelum skrip, satu dengan CSS setelah skrip.
  • Merekam berapa lama untuk menjalankan skrip eksternal dalam <head>menjalankan
  • Mencatat berapa lama waktu yang dibutuhkan untuk skrip inline <body>untuk dieksekusi, yang analog dengan DOMReady.
  • Tertunda mengirim CSS dan / atau skrip ke browser sebanyak 500 ms.
  • Lakukan pengujian 20 kali dalam 3 browser utama.

Hasil

Pertama, dengan file CSS tertunda sebanyak 500 ms:

     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

Selanjutnya, saya mengatur jQuery untuk menunda 500ms daripada 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

Akhirnya, saya menetapkan kedua jQuery dan CSS untuk menunda oleh 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

Kesimpulan

Pertama, penting untuk dicatat bahwa saya beroperasi di bawah asumsi bahwa Anda memiliki skrip yang terletak di dalam <head>dokumen Anda (sebagai lawan dari akhir <body>). Ada berbagai argumen tentang mengapa Anda mungkin menautkan ke skrip Anda di <head>bagian akhir dokumen, tetapi itu di luar cakupan jawaban ini. Ini hanya tentang apakah <script>s harus pergi sebelum <link>s di <head>.

Di peramban DESKTOP modern, sepertinya menautkan ke CSS terlebih dahulu tidak pernah memberikan peningkatan kinerja. Menempatkan CSS setelah skrip memberi Anda jumlah keuntungan sepele saat CSS dan skrip ditunda, tetapi memberi Anda keuntungan besar saat CSS tertunda. (Ditunjukkan olehlast kolom di set hasil pertama.)

Mengingat bahwa menautkan ke CSS terakhir tampaknya tidak mengganggu kinerja tetapi dapat memberikan keuntungan dalam keadaan tertentu, Anda harus menautkan ke stylesheet eksternal setelah Anda menautkan ke skrip eksternal hanya pada browser desktop jika kinerja browser lama tidak menjadi masalah. Baca terus untuk situasi seluler.

Mengapa?

Secara historis, ketika browser menemukan <script>tag yang menunjuk ke sumber daya eksternal, browser akan berhenti mem-parsing HTML, mengambil skrip, menjalankannya, lalu melanjutkan mem-parsing HTML. Sebaliknya, jika browser menemukan <link>untuk stylesheet eksternal, itu akan melanjutkan penguraian HTML saat mengambil file CSS (secara paralel).

Oleh karena itu, saran yang diulang secara luas untuk mengutamakan stylesheet - mereka akan unduh terlebih dahulu, dan skrip pertama untuk mengunduh dapat dimuat secara paralel.

Namun, browser modern (termasuk semua browser yang saya uji dengan di atas) telah menerapkan penguraian spekulatif , di mana browser "melihat ke depan" dalam HTML dan mulai mengunduh sumber daya sebelum skrip mengunduh dan mengeksekusi.

Di browser lama tanpa penguraian spekulatif, menempatkan skrip terlebih dahulu akan memengaruhi kinerja karena mereka tidak akan mengunduh secara paralel.

Dukungan Browser

Penguraian spekulatif pertama kali diterapkan di: (bersama dengan persentase pengguna browser desktop di seluruh dunia menggunakan versi ini atau lebih besar pada Jan 2012)

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

Secara total, sekitar 85% browser desktop yang digunakan saat ini mendukung pemuatan spekulatif. Menempatkan skrip sebelum CSS akan memiliki penalti kinerja pada 15% pengguna secara global ; YMMV berdasarkan audiens spesifik situs Anda. (Dan ingat angka itu menyusut.)

Pada peramban seluler, agak sulit untuk mendapatkan angka pasti hanya karena seberapa heterogennya peramban seluler dan lanskap OS. Karena rendering spekulatif diterapkan di WebKit 525 (dirilis Mar 2008), dan hampir setiap browser seluler yang berharga didasarkan pada WebKit, kita dapat menyimpulkan bahwa "sebagian besar" browser seluler harus mendukungnya. Menurut quirksmode , iOS 2.2 / Android 1.0 menggunakan WebKit 525. Saya tidak tahu seperti apa Windows Phone itu.

Namun, saya menjalankan tes pada perangkat Android 4 saya, dan sementara saya melihat angka yang mirip dengan hasil desktop, saya menghubungkannya dengan debugger jarak jauh baru yang fantastis di Chrome untuk Android, dan tab Network menunjukkan bahwa browser benar-benar menunggu untuk mengunduh. CSS hingga JavaScripts dimuat sepenuhnya - dengan kata lain, bahkan versi terbaru WebKit untuk Android tampaknya tidak mendukung penguraian spekulatif. Saya menduga itu mungkin dimatikan karena CPU, memori, dan / atau kendala jaringan yang melekat pada perangkat seluler.

Kode

Maafkan kecerobohan - ini adalah Q&P.

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 adalah jquery-1.7.1.min.js

josh3736
sumber
137
ini jawaban yang fantastis, terima kasih sudah menggunakan sains! Per hasil Anda "di peramban modern, sepertinya menautkan ke CSS dulu tidak pernah memberikan peningkatan kinerja" , saya pikir jawaban untuk judul pertanyaan adalah ya , saran lama CSS pertama jelas tidak valid.
Jeff Atwood
Mengenai pembaruan @ josh3736 tentang kebalikan pada ponsel ... ini adalah kasus untuk tidak melompat pada perubahan signifikan ini. Saya ingin tahu bagaimana perilaku peramban seluler lainnya (webkit, tokek, presto, trisula, dll.) Karena kinerja di seluler sering kali lebih penting.
scunliffe
1
Anda juga harus mencoba menambahkan beberapa kelambatan untuk mencetak css / js, untuk mensimulasikan kecepatan server lambat.
kirb
1
"Pertama, penting untuk dicatat bahwa saya beroperasi di bawah asumsi bahwa Anda memiliki skrip yang terletak di dalam <head>dokumen Anda (sebagai lawan dari akhir <body>)." Saya akan menyoroti itu jauh sebelumnya dalam jawaban, seperti di atas. Termasuk scriptdalam headyang merujuk ke file eksternal hampir tidak pernah benar, dari hampir semua perspektif (tentu saja bukan kinerja). Saya tidak ingat pernah melakukannya di kehidupan nyata. Mungkin satu atau dua baris skrip inline , tapi hanya itu. Defaultnya, tanpa alasan yang sangat bertentangan, harus menjadi akhir dari tubuh.
TJ Crowder
1
Dipilih mundur, jQuery bukan JavaScript dan hanya menggembungkan halaman lebih lanjut karena itu hasil menggunakannya tidak objektif.
John
303

Ada dua alasan utama untuk menempatkan CSS sebelum JavaScript.

  1. Browser lama (Internet Explorer 6-7, Firefox 2, dll.) Akan memblokir semua unduhan berikutnya ketika mereka mulai mengunduh skrip. Jadi, jika Anda a.jsmengikuti b.cssmereka diunduh secara berurutan: pertama a lalu b. Jika Anda b.cssmengikuti a.jsmereka diunduh secara paralel sehingga halaman dimuat lebih cepat.

  2. Tidak ada yang dirender sampai semua stylesheet diunduh - ini benar di semua browser. Skrip berbeda - mereka memblokir rendering semua elemen DOM yang berada di bawah tag skrip di halaman. Jika Anda meletakkan skrip Anda di HEAD maka itu berarti seluruh halaman diblokir dari rendering sampai semua stylesheet dan semua skrip diunduh. Meskipun masuk akal untuk memblokir semua rendering untuk stylesheet (sehingga Anda mendapatkan gaya yang benar pertama kali dan menghindari flash konten yang tidakstyle FOUC), tidak masuk akal untuk memblokir rendering seluruh halaman untuk skrip. Seringkali skrip tidak memengaruhi elemen DOM atau hanya sebagian elemen DOM. Cara terbaik untuk memuat skrip serendah mungkin di halaman, atau bahkan lebih baik memuatnya secara tidak sinkron.

Sangat menyenangkan untuk membuat contoh dengan Cuzillion . Misalnya, halaman ini memiliki skrip di HEAD sehingga seluruh halaman kosong sampai selesai mengunduh. Namun, jika kita memindahkan skrip ke ujung BODY, blok header halaman di-render karena elemen-elemen DOM tersebut muncul di atas tag SCRIPT, seperti yang dapat Anda lihat di halaman ini .

Steve Souders
sumber
10
Steve yang terhormat mengalahkan saya untuk jawabannya, tetapi saya akan menambahkan artikel yang relevan dengan apa yang ia sebutkan: stevesouders.com/blog/2009/04/27/…
Juan Pablo Buritica
4
lihat browser mana yang mendukung asyncatribut, yang direkomendasikan Steve di sini ketika ia mengatakan "lebih baik memuatnya secara tidak sinkron" - stackoverflow.com/questions/1834077/…
Jeff Atwood
Hai, bisakah Anda memberi tahu saya mengapa ada orang yang menautkan file CSS dengan @importarahan?
Josh Stodola
6
Apa sumber untuk 2), dan jika itu benar, dapatkah Anda menjelaskan mengapa kadang-kadang suatu halaman selesai memuat konten, maka CSS diterapkan satu atau dua detik kemudian? (Ini jarang terjadi, pada halaman saya sendiri di mana CSS berada di tag <head>)
Izkata
2
Jadi kita harus meletakkan jQuery+ jQuery UI+ $(document).ready(function () { });di akhir halaman? Apakah akan selalu bekerja seperti yang diharapkan?
Olivier Pons
42

Saya tidak akan terlalu menekankan pada hasil yang Anda dapatkan, saya percaya itu subjektif, tapi saya punya alasan untuk menjelaskan Anda bahwa lebih baik dimasukkan ke dalam CSS sebelum js.

Selama memuat situs web Anda, ada dua skenario yang akan Anda lihat:

KASUS 1: layar putih> situs unstyled> situs ditata> interaksi> gaya dan website interaktif

KASUS 2: layar putih> situs unstyled> interaksi> situs ditata> bergaya dan interaktif situs


saya jujur tidak bisa membayangkan orang memilih Kasus 2. Ini berarti bahwa pengunjung yang menggunakan koneksi internet lambat akan dihadapkan dengan situs web tanpa gaya, yang memungkinkan mereka untuk berinteraksi dengannya menggunakan Javascript (karena itu sudah dimuat). Selain itu, jumlah waktu yang dihabiskan untuk melihat situs web yang tidak bergaya akan dimaksimalkan dengan cara ini. Mengapa ada yang mau itu?

Ini juga berfungsi lebih baik sebagai status jQuery

"Saat menggunakan skrip yang mengandalkan nilai properti gaya CSS, penting untuk mereferensikan stylesheet eksternal atau elemen gaya embed sebelum merujuk skrip".

Ketika file dimuat dalam urutan yang salah (JS pertama, lalu CSS), kode Javascript apa pun yang mengandalkan properti yang diatur dalam file CSS (misalnya lebar atau tinggi div) tidak akan dimuat dengan benar. Tampaknya dengan urutan pemuatan yang salah, properti yang benar 'terkadang' diketahui oleh Javascript (mungkin ini disebabkan oleh kondisi balapan?). Efek ini tampak lebih besar atau lebih kecil tergantung pada browser yang digunakan.

defau1t
sumber
2
Bagaimana Anda menjamin semua css dimuat sebelum javascript dijalankan? Bisakah kamu? atau javascript Anda harus cukup kuat untuk menghadapi situasi di mana gaya mungkin tidak dimuat.
Jonnio
@ Jonnio Jika JS Anda memiliki ketergantungan, maka Anda harus membuat ketergantungan itu secara eksplisit. Kalau tidak, Anda akan selalu memiliki masalah waktu yang langka. Modul ES6 adalah cara yang baik untuk mewujudkannya, tetapi ada banyak perpustakaan yang dapat digunakan juga.
kmkemp
26

Apakah tes Anda dilakukan di komputer pribadi Anda, atau di server web? Itu adalah halaman kosong, atau apakah itu sistem online yang kompleks dengan gambar, database, dll.? Apakah skrip Anda melakukan hover event action sederhana, atau apakah itu komponen inti bagaimana situs web Anda membuat dan berinteraksi dengan pengguna? Ada beberapa hal yang perlu dipertimbangkan di sini, dan relevansi rekomendasi ini hampir selalu menjadi aturan ketika Anda menjelajah ke pengembangan web kaliber tinggi.

Tujuan dari "menempatkan stylesheet di bagian atas dan skrip di bagian bawah" aturan adalah, secara umum, itu adalah cara terbaik untuk mencapai rendering progresif yang optimal , yang sangat penting bagi pengalaman pengguna.

Selain itu: menganggap tes Anda valid, dan Anda benar-benar menghasilkan hasil yang bertentangan dengan aturan populer, itu tidak mengejutkan, sungguh. Setiap situs web (dan semua yang diperlukan untuk membuat semuanya muncul di layar pengguna) berbeda dan Internet terus berkembang.

minggu
sumber
1
Saya menghargai poin yang Anda buat dalam huruf tebal, tetapi OP sedang berbicara tentang apa yang terjadi ketika Anda memvariasikan urutan dengan keduanya di bagian atas, maupun di bagian bawah.
nnnnnn
1
Dengan demikian, "menganggap tes [nya] valid."
skippr
21

Saya menyertakan file CSS sebelum Javascript untuk alasan yang berbeda.

Jika Javascript saya perlu melakukan pengukuran dinamis dari beberapa elemen halaman (untuk kasus sudut di mana CSS benar-benar utama di belakang) maka memuat CSS setelah JS russing dapat menyebabkan kondisi balapan, di mana elemen diubah ukurannya sebelum gaya CSS diterapkan dan dengan demikian terlihat aneh ketika gaya akhirnya masuk. Jika saya memuat CSS sebelumnya saya dapat menjamin bahwa semuanya berjalan dalam urutan yang dimaksudkan dan bahwa tata letak akhir adalah apa yang saya inginkan.

hugomg
sumber
2
ini akan rusak suatu hari di beberapa browser. Saya tidak menebak.
jcolebrand
1
jcolebrand: Ya, saya pikir saya belum minum kopi yang cukup ketika saya menulis ini. (Dalam retrospeksi, saya kira hal-hal penting hanya untuk menghindari pemuatan dinamis CSS dan menempatkan JS dalam acara domReady jika Anda perlu melakukan ukuran dinamis)
hugomg
Skrip seharusnya tidak mengubah tampilan apa pun. Itu pekerjaan CSS. HTML = konten, CSS = Cara menampilkan konten, javascript mengubah konten secara dinamis. Juga js seharusnya hanya bertindak setelah (atau sementara) DOMContentLoaded dipecat dengan beberapa situasi kecil tapi sangat spesifik.
brunoais
@brunoais: Beberapa tata letak hanya dapat dibuat dengan Javascript. Sebagai contoh, segala sesuatu yang perlu diubah ukurannya secara dinamis harus dibuat melalui Javascript dan beberapa hal (seperti memiliki ukuran 100% - 20px) perlu Javascript dilakukan dengan mudah di browser lama.
hugomg
@missingno Dalam kasus tersebut, cukup gunakan acara DOMContentLoaded. Tapi aku mengerti maksudmu. (Bodoh IE!)
brunoais
10

Apakah rekomendasi untuk memasukkan CSS sebelum JavaScript tidak valid?

Tidak jika Anda memperlakukannya hanya sebagai rekomendasi. Tetapi jika Anda memperlakukannya sebagai aturan yang keras dan cepat ?, ya, itu tidak valid.

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

Stylesheet memuat eksekusi skrip blok, jadi jika Anda memiliki <script> setelah <link rel="stylesheet" ...>halaman tidak akan menyelesaikan parsing - dan DOMContentLoaded tidak akan diaktifkan - sampai stylesheet dimuat.

Tampaknya Anda perlu tahu apa yang diandalkan oleh setiap skrip dan memastikan bahwa eksekusi skrip ditunda hingga setelah acara penyelesaian yang tepat. Jika skrip hanya bergantung pada DOM, skrip dapat dilanjutkan di ondomready / domcontentloaded, jika itu bergantung pada gambar yang akan dimuat atau stylesheet yang akan diterapkan, maka jika saya membaca referensi di atas dengan benar, kode itu harus ditunda sampai peristiwa onload.

Saya tidak berpikir bahwa satu ukuran kaus kaki cocok untuk semua, meskipun itulah cara mereka dijual dan saya tahu bahwa satu ukuran sepatu tidak cocok untuk semua. Saya tidak berpikir bahwa ada jawaban pasti untuk memuat pertama, gaya atau skrip. Ini lebih merupakan kasus per kasus keputusan apa yang harus dimuat dalam urutan apa dan apa yang bisa ditunda sampai nanti karena tidak berada di "jalur kritis".

Untuk berbicara dengan pengamat yang berkomentar bahwa lebih baik untuk menunda kemampuan pengguna untuk berinteraksi sampai lembar itu cantik. Ada banyak dari Anda di luar sana dan Anda mengganggu rekan-rekan Anda yang merasakan hal sebaliknya. Mereka datang ke situs untuk mencapai tujuan dan menunda kemampuan mereka untuk berinteraksi dengan situs sambil menunggu hal-hal yang tidak masalah untuk menyelesaikan pemuatan sangat frustasi. Saya tidak mengatakan bahwa Anda salah, hanya bahwa Anda harus sadar bahwa ada faksi lain yang ada yang tidak berbagi prioritas Anda.

Pertanyaan ini terutama berlaku untuk semua iklan yang ditempatkan di situs web. Saya akan senang jika penulis situs hanya memberikan div placeholder untuk konten iklan dan memastikan bahwa situs mereka dimuat dan interaktif sebelum menyuntikkan iklan dalam acara onload. Bahkan kemudian saya ingin melihat iklan dimuat secara serial bukan sekaligus karena mereka memengaruhi kemampuan saya untuk bahkan menggulir konten situs saat iklan kembung dimuat. Tapi itu hanya sudut pandang satu orang.

  • Ketahui pengguna Anda dan apa nilainya.
  • Ketahui pengguna Anda dan lingkungan penelusuran apa yang mereka gunakan.
  • Ketahui apa yang dilakukan oleh setiap file, dan apa saja persyaratannya. Membuat semuanya berfungsi akan lebih diutamakan daripada kecepatan dan cantik.
  • Gunakan alat yang menunjukkan garis waktu jaringan saat mengembangkan.
  • Uji di setiap lingkungan yang digunakan pengguna Anda. Mungkin diperlukan untuk secara dinamis (sisi server, saat membuat halaman) mengubah urutan pemuatan berdasarkan lingkungan pengguna.
  • Jika ragu, ubah urutan dan ukur lagi.
  • Ada kemungkinan bahwa gaya dan skrip yang dicampur dalam urutan pemuatan akan optimal; tidak semuanya, kemudian yang lainnya.
  • Eksperimen bukan hanya urutan apa untuk memuat file tetapi di mana. Kepala? Di dalam tubuh? Setelah Tubuh? Siap DOM / Dimuat? Sarat?
  • Pertimbangkan opsi async dan tunda saat yang tepat untuk mengurangi penundaan internet yang akan dialami pengguna sebelum dapat berinteraksi dengan halaman. Tes untuk menentukan apakah mereka membantu atau menyakiti.
  • Akan selalu ada trade off untuk dipertimbangkan ketika mengevaluasi urutan beban optimal. Cantik vs Responsif menjadi hanya satu.
Ted Cohen
sumber
1
Artikel yang ditautkan tidak lagi mengklaim "Stylesheet memuat eksekusi skrip". Apakah itu tidak benar lagi?
Greg
@Reg - Itu masih benar. Skrip harus dapat meminta atribut DOM .style, sehingga stylesheet masih memblokir eksekusi skrip. Mereka mungkin tidak memblokir pemuatan skrip , jika mereka pintar, tetapi mereka akan memblokir script.onLoad acara.
Jimmy Breck-McKye
10

Diperbarui 2017-12-16

Saya tidak yakin tentang tes di OP. Saya memutuskan untuk bereksperimen sedikit dan akhirnya menghancurkan beberapa mitos.

Synchronous <script src...>akan memblokir pengunduhan sumber daya di bawahnya sampai diunduh dan dieksekusi

Ini tidak lagi benar . Lihatlah air terjun yang dihasilkan oleh 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>

Inspektur jaringan Chrome -> air terjun

<link rel=stylesheet> tidak akan memblokir unduhan dan pelaksanaan skrip di bawahnya

Ini salah . Stylesheet tidak akan memblokir unduhan tetapi akan memblokir eksekusi skrip ( sedikit penjelasan di sini ). Lihat grafik kinerja yang dihasilkan oleh 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>

Alat dev Chrome -> kinerja


Dengan mengingat hal di atas, hasil dalam OP dapat dijelaskan sebagai berikut:

CSS Pertama:

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

JS First:

JS Download   400ms:<-------------------------------------->
CSS Download  500ms:<------------------------------------------------>
JS Execution 1000ms:                                        <-------------------------------------------------------------------------------------------------->
DOM Ready   @1400ms:                                                                                                                                            
Salman A
sumber
Itu juga mengapa document.write () adalah salah satu ide terburuk yang pernah dibuat untuk HTMLDOM.
brunoais
1
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/... Mengapa asumsi yang sama tidak berlaku untuk JS? Tidak masuk akal bagi saya, urutan eksekusi JS tidak mengatakan apa-apa tentang tujuan itu.
Thorsten Schöning
4

Saya tidak begitu yakin bagaimana pengujian 'render' Anda saat menggunakan java script. Namun pertimbangkan ini

Satu halaman di situs Anda adalah 50k yang tidak masuk akal. Pengguna berada di pantai timur saat server Anda berada di barat. MTU jelas bukan 10rb sehingga akan ada beberapa perjalanan bolak-balik. Mungkin butuh 1/2 detik untuk menerima halaman dan stylesheet Anda. Biasanya javascript (untuk saya) (melalui plugin jquery dan semacamnya) lebih dari sekadar CSS. Ada juga apa yang terjadi ketika koneksi internet Anda tercekik di tengah-tengah halaman tetapi mari kita abaikan itu (itu terjadi pada saya sesekali dan saya percaya css merender tetapi saya tidak 100% yakin).

Karena css ada di kepala mungkin ada koneksi tambahan untuk mendapatkannya yang berarti berpotensi menyelesaikan sebelum halaman melakukannya. Bagaimanapun selama jenis sisa halaman mengambil dan file javascript (yang lebih banyak byte) halaman tidak di-style yang membuat situs / koneksi tampak lambat.

BAHKAN JIKA penerjemah JS menolak untuk memulai sampai CSS selesai waktu yang dibutuhkan untuk mengunduh kode javascript terutama ketika jauh dari server memotong waktu css yang akan membuat situs terlihat tidak cantik.

Ini optimasi kecil tapi itulah alasannya.


sumber
1
servernya ada di pantai timur, fwiw. Anda juga, tampaknya, tidak menyadari fakta bahwa mereka sekarang menggunakan CDN.
jcolebrand
3

Berikut ini adalah RINGKASAN dari semua jawaban utama di atas (atau mungkin di bawah nanti :)

Untuk peramban modern, letakkan css di mana pun Anda suka. Mereka akan menganalisis file html Anda (yang mereka sebut parsing spekulatif ) dan mulai mengunduh css secara paralel dengan parsing html.

Untuk browser lama, terus letakkan css di atas (jika Anda tidak ingin menampilkan halaman yang telanjang tetapi interaktif terlebih dahulu).

Untuk semua browser, letakkan javascript sejauh mungkin di halaman, karena itu akan menghentikan penguraian html Anda. Lebih disukai, unduh secara asinkron (mis., Panggilan ajax)

Ada juga, beberapa hasil eksperimental untuk kasus tertentu yang mengklaim menempatkan javascript pertama (sebagai lawan dari kearifan tradisional menempatkan CSS pertama) memberikan kinerja yang lebih baik tetapi tidak ada alasan logis yang diberikan untuk itu, dan tidak memiliki validasi mengenai penerapan yang luas, sehingga Anda dapat abaikan saja untuk sekarang.

Jadi, untuk menjawab pertanyaan: Ya. Rekomendasi untuk menyertakan CSS sebelum JS tidak valid untuk browser modern. Letakkan CSS di mana pun Anda suka, dan letakkan JS di akhir, mungkin.

mehmet
sumber
1

Steve Souders telah memberikan jawaban yang pasti tetapi ...

Saya bertanya-tanya apakah ada masalah dengan tes asli Sam dan pengulangan Josh.

Kedua tes tampaknya telah dilakukan pada koneksi latensi rendah di mana pengaturan koneksi TCP akan memiliki biaya sepele.

Bagaimana ini mempengaruhi hasil tes saya tidak yakin dan saya ingin melihat air terjun untuk tes melalui koneksi latensi 'normal' tapi ...

File pertama yang diunduh harus menggunakan koneksi yang digunakan untuk halaman html, dan file kedua yang diunduh akan mendapatkan koneksi baru. (Menyiram perubahan awal yang dinamis, tapi itu tidak dilakukan di sini)

Pada browser yang lebih baru, koneksi TCP kedua dibuka secara spekulatif sehingga overhead koneksi berkurang / hilang, pada browser lama ini tidak benar dan koneksi kedua akan memiliki overhead yang sedang dibuka.

Cukup bagaimana / jika ini mempengaruhi hasil tes saya tidak yakin.

Andy Davies
sumber
tidak mengikuti, kecuali jika Anda memiliki pipelining yang sangat jarang Anda sangat tidak mungkin untuk mendapatkan pengaturan koneksi berkurang ... setuju tes harus diulang pada latensi rendah
Sam Saffron
Jika Anda melihat air terjun ini, Anda dapat melihat di mana Chrome secara spekulatif membuka koneksi kedua sebelum diperlukan webpagetest.org/result/… (IE9 melakukan hal yang sama) ... Saya memikirkan latensi normal untuk keperluan TCP daripada rendah - seperti apa lingkungan di mana tes dilakukan?
Andy Davies
2
Re: "Steve Souders sudah memberikan jawaban pasti tetapi ..." Masalahnya dengan evolusi web adalah bahwa tidak ada jawaban pasti. :) Ada 3-4 cara memuat skrip dan banyak hal berubah. Semantik yang sebenarnya sebenarnya seharusnya bagi Steve untuk mengatakan "Letakkan CSS sebelum Sinkronisasi JavaScript" Jika tidak, orang salah dengan menggeneralisasi karena menjadi aturan untuk semua skrip ...
hexalys
Ya tetapi kebanyakan orang hanya memasukkan skrip secara sinkron sehingga saran Steve baik untuk yang belum tahu.
Andy Davies
1

Saya pikir ini tidak akan berlaku untuk semua kasus. Karena css akan mengunduh paralel tetapi js tidak bisa. Pertimbangkan untuk kasus yang sama,

Alih-alih memiliki css tunggal, ambil 2 atau 3 file css dan coba cara ini,

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

Saya yakin css..css..js akan memberikan hasil yang lebih baik daripada yang lainnya.

harishkumar329
sumber
0

Kita harus ingat bahwa browser baru telah bekerja pada mesin Javascript mereka, parser mereka dan sebagainya, mengoptimalkan kode umum dan masalah markup sedemikian rupa sehingga masalah yang dialami pada browser kuno seperti <= IE8 tidak lagi relevan, tidak hanya dengan salam untuk markup tetapi juga untuk menggunakan variabel JavaScript, pemilih elemen dll. Saya bisa melihat di masa depan yang tidak terlalu jauh situasi di mana teknologi telah mencapai titik di mana kinerja tidak benar-benar masalah lagi.

George Katsanos
sumber
Kinerja selalu menjadi masalah. Saya hanya hampir mengabaikan browser yang tidak mengikuti spesifikasi yang ada. Saya hanya menyiapkan kode saya sedemikian rupa sehingga orang-orang yang mengikuti spec bekerja dengan kecepatan penuh dan yang lain saya hanya melakukan itu berfungsi. Jadi, misalnya, jika itu hanya berfungsi di IE8, semuanya ok.
brunoais
-5

Secara pribadi, saya tidak akan terlalu menekankan pada "kearifan rakyat". Apa yang mungkin benar di masa lalu mungkin tidak benar sekarang. Saya akan berasumsi bahwa semua operasi yang berkaitan dengan interpretasi dan rendering halaman web sepenuhnya tidak sinkron ("mengambil" sesuatu dan "menindaklanjutinya" adalah dua hal yang sepenuhnya berbeda yang mungkin ditangani oleh utas yang berbeda, dll. ), Dan dalam hal apa pun sepenuhnya di luar kendali Anda atau masalah Anda.

Saya akan meletakkan referensi CSS di bagian "head" dokumen, bersama dengan referensi ke skrip eksternal. (Beberapa skrip mungkin menuntut untuk ditempatkan di badan, dan jika demikian, mewajibkannya.)

Di luar itu ... jika Anda mengamati bahwa "ini tampaknya lebih cepat / lebih lambat dari itu, pada browser ini / itu," memperlakukan pengamatan ini sebagai keingintahuan yang menarik tetapi tidak relevan dan jangan biarkan itu memengaruhi keputusan desain Anda. Terlalu banyak hal berubah terlalu cepat. (Adakah yang mau bertaruh berapa menit sebelum tim Firefox mengeluarkan produk mereka untuk sementara waktu? Yup, saya juga.)

pengguna106701
sumber