프로그래밍 언어/HTML,CSS,JS

CSS가 항상 Javascript보다 먼저 나와야 하는 이유

Rateye 2021. 11. 17. 10:48
728x90
반응형
질문 : CSS가 항상 Javascript보다 우선해야합니까?

온라인의 수많은 곳에서 JavaScript 이전에 CSS를 포함하라는 권장 사항을 보았습니다. 그 이유는 일반적으로 다음 과 같은 형식입니다 .

CSS와 자바 스크립트를 주문할 때 CSS가 먼저 나오기를 원합니다. 그 이유는 렌더링 스레드에 페이지를 렌더링하는 데 필요한 모든 스타일 정보가 있기 때문입니다. JavaScript 포함이 먼저 오는 경우 JavaScript 엔진은 다음 리소스 세트로 계속 진행하기 전에 모든 것을 구문 분석해야합니다. 이것은 렌더링 스레드가 필요한 모든 스타일을 가지고 있지 않기 때문에 페이지를 완전히 표시 할 수 없음을 의미합니다.

내 실제 테스트는 매우 다른 것을 보여줍니다.

My test harness

다음 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 은 CSS 전송을 500ms 지연시킵니다.

다음 페이지를 사용하여 테스트합니다.

<!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 초가 걸립니다.

CSS 우선

JavaScript를 먼저 포함하면 페이지를 렌더링하는 데 1.4 초가 걸립니다.

JavaScript 우선

Chrome, Firefox 및 Internet Explorer에서 비슷한 결과를 얻습니다. 그러나 Opera에서는 순서가 중요하지 않습니다.

일어나는 것처럼 보이는 것은 모든 CSS가 다운로드 될 때까지 JavaScript 인터프리터가 시작을 거부한다는 것입니다. 따라서 JavaScript 스레드가 더 많은 런타임을 얻음에 따라 JavaScript 포함을 먼저 사용하는 것이 더 효율적으로 보입니다.

내가 뭔가를 놓치고 있는데, JavaScript 포함 전에 CSS 포함을 배치하라는 권장 사항이 올바르지 않습니까?

비동기를 추가하거나 setTimeout을 사용하여 렌더링 스레드를 비우거나 바닥 글에 JavaScript 코드를 넣거나 JavaScript 로더를 사용할 수 있다는 것은 분명합니다. 여기서 요점은 머리에서 필수 JavaScript 비트와 CSS 비트의 순서에 관한 것입니다.

 

반응형

 

답변

이것은 매우 흥미로운 질문입니다. 나는 항상 내 CSS <link href="..."> 를 내 JS <script src="..."> 앞에 두었습니다. "나는 그것이 더 낫다는 것을 한 번 읽었 기 때문입니다." 그래서, 당신이 옳습니다. 실제 조사를 할 때입니다!

Node에서 자체 테스트 하네스를 설정했습니다 (아래 코드). 기본적으로 나는 :

  • HTTP 캐싱이 없는지 확인하여 페이지가로드 될 때마다 브라우저가 전체 다운로드를 수행해야합니다.
  • 현실을 시뮬레이션하기 위해 jQuery와 H5BP CSS를 포함했습니다 (따라서 구문 분석 할 스크립트 / CSS의 양이 적당합니다).
  • 두 페이지를 설정합니다. 하나는 스크립트 이전에 CSS를 사용하고 다른 하나는 스크립트 이후에 CSS를 사용합니다.
  • <head> 의 외부 스크립트를 실행하는 데 걸린 시간을 기록했습니다.
  • DOMReady <body> 의 인라인 스크립트를 실행하는 데 걸린 시간을 기록했습니다.
  • 브라우저에 CSS 및 / 또는 스크립트 전송을 500ms 지연했습니다.
  • 3 개의 주요 브라우저에서 테스트를 20 회 실행했습니다.

Results

먼저 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

다음으로 CSS 대신 500ms 지연되도록 jQuery를 설정했습니다.

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

결론

<head> 에 스크립트가 있다는 가정하에 작업하고 있다는 점에 유의하는 것이 중요합니다 <body> 의 끝이 아니라). <head> 의 스크립트에 연결하는 이유에 대한 다양한 주장이 있지만이 답변의 범위를 벗어납니다. <head> 에서 <script> <link> 앞에 와야하는지 여부에 관한 것입니다.

최신 데스크톱 브라우저에서는 CSS에 연결하는 것이 성능 향상을 제공 하지 않는 것처럼 보입니다. 스크립트 뒤에 CSS를 배치하면 CSS와 스크립트가 모두 지연 될 때 약간의 이득을 얻을 수 있지만 CSS가 지연되면 큰 이득을 얻을 수 있습니다. (첫 번째 결과 집합의 last 열에 표시됩니다.)

마지막으로 CSS에 연결하는 것이 성능을 저하 시키지는 않지만 특정 상황에서 이점을 제공 할 수 있으므로 이전 브라우저의 성능이 문제가되지 않는 경우 데스크톱 브라우저에서만 외부 스크립트에 연결 한 후 외부 스타일 시트에 연결해야합니다. 모바일 상황에 대해 읽어보십시오.

이유

역사적으로 브라우저가 외부 리소스를 가리키는 <script> 태그를 발견하면 브라우저는 HTML 구문 분석을 중지 하고 스크립트를 검색하고 실행 한 다음 HTML 구문 분석을 계속했습니다. 반대로 브라우저가 외부 스타일 시트에 대한 <link> 를 발견하면 CSS 파일을 가져 오는 동안 (병렬로) HTML을 계속 구문 분석합니다.

따라서 스타일 시트를 먼저 배치하라는 널리 반복되는 조언은 먼저 다운로드하고 다운로드 할 첫 번째 스크립트를 병렬로로드 할 수 있습니다.

그러나 최신 브라우저 (위에서 테스트 한 모든 브라우저 포함)는 브라우저가 HTML에서 "미리 살펴보고"스크립트를 다운로드하고 실행 하기 전에 리소스를 다운로드하기 시작하는 추론 적 구문 분석을 구현했습니다.

추측 적 구문 분석이없는 오래된 브라우저에서 스크립트를 먼저 배치하면 병렬로 다운로드되지 않으므로 성능에 영향을 미칩니다.

브라우저 지원

추측 파싱은 다음에서 처음 구현되었습니다. (2012 년 1 월 현재이 버전 이상을 사용하는 전 세계 데스크톱 브라우저 사용자의 비율과 함께)

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

현재 사용중인 데스크톱 브라우저의 약 85 %가 예측 로딩을 지원합니다. CSS 앞에 스크립트를 넣으면 전 세계 사용자의 15 %에 대한 성능 저하가 발생합니다. 사이트의 특정 잠재 고객을 기반으로 한 YMMV. (그리고 숫자가 줄어들고 있음을 기억하십시오.)

모바일 브라우저에서는 모바일 브라우저와 OS 환경이 얼마나 이질적인 지로 인해 정확한 수치를 얻는 것이 조금 더 어렵습니다. 추측 적 렌더링은 WebKit 525 (2008 년 3 월 출시)에서 구현되었고 거의 모든 가치있는 모바일 브라우저가 WebKit을 기반으로했기 때문에 "대부분의"모바일 브라우저 가이를 지원해야한다고 결론을 내릴 수 있습니다. quirksmode 에 따르면 iOS 2.2 / Android 1.0은 WebKit 525를 사용합니다. Windows Phone이 어떻게 생겼는지 모르겠습니다.

하지만 내 Android 4 기기에서 테스트를 실행했는데 데스크톱 결과와 비슷한 수치를 보았지만 Android 용 Chrome의 환상적인 새 원격 디버거 에 연결했고 네트워크 탭에 브라우저가 실제로 다운로드를 기다리고 있음이 표시되었습니다. 즉, 최신 버전의 Android 용 WebKit조차도 추론 적 구문 분석을 지원하지 않는 것으로 보입니다. 모바일 장치 고유의 CPU, 메모리 및 / 또는 네트워크 제약으로 인해 꺼져있을 수 있습니다.

Code

엉성함을 용서하십시오 – 이것은 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[

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였습니다.

출처 : https://stackoverflow.com/questions/9271276/should-css-always-preceed-javascript
728x90
반응형