Чи повинен CSS завжди передувати Javascript?


897

У незліченних місцях в Інтернеті я побачив рекомендацію включати CSS до JavaScript. Міркування, як правило, такої форми :

Що стосується замовлення CSS та JavaScript, ви хочете, щоб ваш CSS став першим. Причина полягає в тому, що в потоці візуалізації є вся інформація про стиль, необхідна для візуалізації сторінки. Якщо JavaScript включає спочатку, движок JavaScript повинен проаналізувати все це, перш ніж перейти до наступного набору ресурсів. Це означає, що нитка візуалізації не може повністю відображати сторінку, оскільки вона не має всіх потрібних їй стилів.

Моє фактичне тестування виявляє щось зовсім інше:

Мій тестовий джгут

Я використовую наступний сценарій 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дає мені затримку 500 мс при передачі CSS.

Я використовую наступну сторінку для тестування.

<!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, однак, замовлення просто не має значення.

Здається, що інтерпретатор JavaScript відмовляється запускатись до завантаження всіх CSS. Отже, здається, що використання JavaScript в першу чергу є більш ефективною, оскільки потік JavaScript отримує більше часу роботи.

Я щось пропускаю, чи рекомендація розміщувати CSS перед тим, як JavaScript включає невірно?

Зрозуміло, що ми можемо додати async або використовувати setTimeout для звільнення потоку візуалізації або введення коду JavaScript у нижній колонтитул або використання завантажувача JavaScript. Суть у тому, щоб впорядкувати основні біти JavaScript та CSS біти в голові.


120
чи є 1511 проти 1422 статистично значущою різницею? Це 6 відсотків. Загальний поріг різниці між показниками середнього та середнього рівня людини становить близько 20 відсотків.
Джефф Етвуд

15
справа в тому, що переупорядкування виключає цю довільну затримку, ви можете встановити затримку на все, що завгодно, це лише демонстрація проблеми.
Сам Шафран

3
ваша затримка була 100 мс? різниця у ваших знімках екрану - 89 мс. У вашій URL-адресі вона є delay=400&amp;jsdelay=1000і delay=500яка ніде не становить 100 мс або 89 мс. Напевно, мені незрозуміло, на які цифри ви посилаєтесь.
Джефф Етвуд

4
"Якщо Javascript включає перше місце, механізм Javascript повинен проаналізувати все це, перш ніж продовжувати переходити до наступного набору ресурсів. Це означає, що нитка візуалізації не може повністю відобразити сторінку, оскільки вона не має всіх потрібних їй стилів. . " - якщо включення JS знаходиться в заголовку, то JS буде виконуватися до того, як сторінка буде виведена незалежно від того, включена функція CSS була до або після.
nnnnnn

162
Не впевнений, чи ви це враховували, але сприйняття часу навантаження теж важливе. Так, наприклад, якщо завантаження CSS спочатку дає вам навіть просто колір / текстуру фону сторінки, це, здається, буде швидше. Абсолютний час завантаження може не свідчити про це.
Ракеш Пай

Відповіді:


712

Це дуже цікаве питання. Я завжди ставлю свої CSS <link href="...">перед своїми JS <script src="...">, тому що "я прочитав один раз, що це краще". Отже, ти маєш рацію; саме час ми робимо деякі фактичні дослідження!

Я встановив власний тестовий джгут в Node (код нижче). В основному, я:

  • Переконайтесь у відсутності кешування HTTP, тому браузер повинен виконувати повне завантаження щоразу при завантаженні сторінки.
  • Для імітації реальності я включив jQuery та H5BP CSS (так що пристойний обсяг сценарію / CSS для розбору)
  • Створіть дві сторінки - одну з CSS перед сценарієм, одну з CSS після скрипту.
  • У записи , скільки часу знадобилося для зовнішнього скрипта в <head>виконання
  • Записано, скільки часу знадобиться вбудованому сценарію у <body>виконанні, що є аналогом DOMReady.
  • Затримка надсилання CSS та / або сценарію до браузера на 500 мс.
  • Тест пройшов 20 разів у трьох основних браузерах.

Результати

По-перше, затримка файлу CSS на 500 мс:

     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 затримку на 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

Нарешті, я встановив і jQuery, і CSS затримку на 500 мс:

     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>слід йти перед <link>s в <head>.

У сучасних браузерах DESKTOP схоже, що посилання на CSS спочатку ніколи не забезпечує підвищення продуктивності. Якщо встановити CSS після скрипту, ви отримаєте тривіальну кількість виграшу, коли і CSS, і сценарій затримуються, але приносять великі вигоди, коли CSS затримується. (Показано lastстовпцями у першому наборі результатів.)

Зважаючи на те, що підключення до CSS останнім не погіршує ефективність роботи, але за певних обставин може принести прибуток, вам слід зв’язатися із зовнішніми таблицями стилів після того, як ви посилаєтесь на зовнішні скрипти лише на браузерах настільних ПК, якщо продуктивність старих браузерів не викликає занепокоєння. Читайте далі про мобільну ситуацію.

Чому?

Історично, коли браузер зіткнувся з <script>тегом, що вказує на зовнішній ресурс, браузер припинить розбір HTML, вилучить скрипт, виконає його, а потім продовжить розбір HTML. На відміну від цього, якщо веб-переглядач зіткнувся з <link>для зовнішньої таблиці стилів, він продовжував би розбирати HTML під час отримання файлу CSS (паралельно).

Отже, широко повторювана порада ставити таблиці таблиць стилів на перше місце - вони завантажуються спочатку, а перший сценарій для завантаження можна завантажувати паралельно.

Однак сучасні браузери (включаючи всі браузери, які я тестував вище) здійснили спекулятивний аналіз , коли браузер "дивиться вперед" в HTML і починає завантажувати ресурси перед завантаженням та виконанням сценаріїв.

У старих браузерах без спекулятивного розбору перше розміщення скриптів вплине на продуктивність, оскільки вони не завантажуватимуться паралельно.

Підтримка браузера

Спекулятивний аналіз вперше був реалізований у: (разом із відсотком світових користувачів настільних браузерів, які користуються цією версією або вище станом на січень 2012 року)

  • Chrome 1 (WebKit 525) (100%)
  • IE 8 (75%)
  • Firefox 3,5 (96%)
  • Сафарі 4 (99%)
  • Opera 11.60 (85%)

Загалом приблизно 85% настільних браузерів, які використовуються сьогодні, підтримують спекулятивне завантаження. За розміщення сценаріїв перед CSS буде накладено штраф на 15% користувачів у всьому світі ; YMMV на основі конкретної аудиторії вашого сайту. (І пам'ятайте, що число зменшується.)

У мобільних браузерах трохи складніше отримати остаточні цифри просто через те, наскільки неоднорідним є мобільний браузер та ландшафт ОС. Оскільки спекулятивна візуалізація була впроваджена в WebKit 525 (випущена в березні 2008 року), і майже кожен мобільний браузер, що стоїть на базі WebKit, можна зробити висновок, що "більшість" мобільних браузерів повинні підтримувати це. За даними quirksmode , iOS 2.2 / Android 1.0 використовує WebKit 525. Я поняття не маю, як виглядає Windows Phone.

Однак я провів тест на своєму пристрої Android 4, і, побачивши номери, схожі на результати на робочому столі, я підключив його до нового фантастичного віддаленого налагоджувача в Chrome для Android, і на вкладці "Мережа" було показано, що браузер насправді чекає завантаження CSS до тих пір, поки JavaScripts повністю не завантажиться - іншими словами, навіть найновіша версія WebKit для Android не підтримує спекулятивний аналіз. Я підозрюю, що це може бути вимкнено через обмеження процесора, пам’яті та / або мережевих обмежень, властивих мобільним пристроям.

Код

Пробачте неохайність - це були питання та розробки.

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


137
це фантастична відповідь, дякую за використання науки! За вашим результатом "у сучасних браузерах виглядає, що посилання на CSS спочатку ніколи не забезпечує підвищення продуктивності" , я вважаю, що відповідь на назву питання - так , стара порада CSS спочатку явно недійсна.
Джефф Етвуд

Що стосується оновлення @ josh3736 щодо зворотного зв'язку для мобільних пристроїв ... це нагода не заважати на значну зміну. Мені буде цікаво, як поводяться інші мобільні веб-переглядачі (webkit, gecko, presto, тризуб тощо), оскільки продуктивність у мобільному часто важливіша.
сканліфф

1
Спробуйте також додати деяку повільність до друку css / js, щоб імітувати швидкість повільного сервера.
kirb

1
"По-перше, важливо зазначити, що я працюю за припущенням, що у вас є сценарії, розташовані в <head>документі (на відміну від кінця документа <body>)." Я б виділив це набагато раніше у відповіді, як у верхній частині. Включаючи scriptв headтому , що відноситься до зовнішнього файл майже ніколи не правильно, з майже будь-якої точки зору (звичайно , не спектакль одного). Я не пригадую, щоб коли-небудь доводилося це робити в реальному житті. Можливо, непарний рядок або два вбудованого сценарію, але це все. За замовчуванням без дуже поважних протилежних причин має бути кінець тіла.
TJ Crowder

1
JQuery з обмеженим голосом - це не JavaScript, а лише додатково розмиває сторінку, тому результати, використовуючи її, не є об'єктивними.
Іван

303

Є дві основні причини ставити CSS перед JavaScript.

  1. Старі браузери (Internet Explorer 6-7, Firefox 2 тощо) заблокували б усі наступні завантаження, коли вони почали завантажувати сценарій. Тож якщо ви a.jsслідуєте за цим, b.cssвони завантажуються послідовно: спочатку a, потім b. Якщо ви b.cssслідуєте за цим, a.jsвони завантажуються паралельно, тому сторінка завантажується швидше.

  2. Нічого не виводиться, поки не завантажуються всі таблиці стилів - це справедливо у всіх браузерах. Сценарії різні - вони блокують візуалізацію всіх елементів DOM, які знаходяться нижче тегу сценарію на сторінці. Якщо ви помістите свої сценарії в HEAD, це означає, що вся сторінка заблокована від візуалізації до моменту завантаження всіх таблиць стилів та всіх сценаріїв. Хоча має сенс блокувати все візуалізацію для таблиць стилів (таким чином, ви отримуєте правильну стилізацію в перший раз і уникаєте спалаху нестилізованого вмісту FOUC), не має сенсу блокувати візуалізацію всієї сторінки для сценаріїв. Часто сценарії не впливають на жодні елементи DOM або просто частину елементів DOM. Найкраще завантажувати сценарії якомога нижче сторінки, а ще краще завантажувати їх асинхронно.

Це цікаво створювати приклади за допомогою Cuzillion . Наприклад, на цій сторінці є скрипт в HEAD, тому вся сторінка порожня, поки не буде завершено завантаження. Однак якщо ми перемістимо скрипт до кінця блоку BODY, заголовок сторінки відображається, оскільки ці елементи DOM виникають над тегом SCRIPT, як ви бачите на цій сторінці .


10
Заслужений Стів побив мене у відповідь, але я додам статтю, що стосується того, що він згадує: stevesouders.com/blog/2009/04/27/…
Juan Pablo Buritica

4
подивіться, які браузери підтримують цей asyncатрибут, який Стів рекомендує тут, коли він говорить "ще краще завантажте їх асинхронно" - stackoverflow.com/questions/1834077/…
Джефф Етвуд

Гей, ви можете мені сказати, чому хто-небудь пов'язує файли CSS з @importдирективами?
Джош Стодола

6
Яке джерело для 2), і якщо це правда, чи можете ви пояснити, чому при нагоді сторінка закінчує завантаження вмісту, тоді CSS застосовується через секунду чи дві? (Це трапляється рідко, на моїх власних сторінках, де CSS був у тегах <head>)
Izkata

2
Таким чином , ми повинні поставити jQuery+ jQuery UI+ $(document).ready(function () { });в кінці сторінки? Чи завжди це буде працювати, як очікувалося?
Олів'є Понс

42

Я б не надто наголошував на результатах, які ви отримали, я вважаю, що це суб'єктивно, але у мене є підстави пояснити вам, що краще поставити в CSS перед js.

Під час завантаження вашого веб-сайту ви побачили два сценарії:

Випадок 1: білий екран> веб - сайт без стилів> стиль сайту> взаємодія> стиль і інтерактивний веб - сайт

ВИПАДОК 2: білий екран> веб - сайт без стилів> взаємодія> стиль сайту> стиль і інтерактивний веб - сайт


, я чесно не можу уявити , щоб хтось вибираючи випадок 2. Це означатиме що відвідувачі, які використовують повільне підключення до Інтернету, зіткнуться з нестиглим веб-сайтом, який дозволяє взаємодіяти з ним за допомогою Javascript (оскільки це вже завантажено). Крім того, таким чином було б збільшено кількість часу, витраченого на перегляд веб-сайту, що не стирається. Чому хтось цього хоче?

Він також працює краще як стан jQuery

"Під час використання скриптів, які покладаються на значення властивостей стилю CSS, важливо посилатися на зовнішні таблиці стилів або вбудовувати елементи стилю перед посиланням на скрипти".

Коли файли завантажуються в неправильному порядку (спочатку JS, потім CSS), будь-який код Javascript, що спирається на властивості, встановлені у файлах CSS (наприклад, ширина або висота ключа), не буде завантажений належним чином. Здається, що з неправильним порядком завантаження правильні властивості «інколи» відомі Javascript (можливо, це викликано умовою перегонів?). Цей ефект здається більшим чи меншим, залежно від використовуваного браузера.


2
Як би ви хотіли гарантувати, що весь CSS завантажений до виконання JavaScript? Ти можеш? або якщо ваш JavaScript буде достатньо надійним, щоб вирішити ситуацію, коли стилі не обов'язково завантажуються.
Джонніо

@Jonnio Якщо ваш JS має залежність, то слід зробити цю залежність явною. В іншому випадку у вас завжди будуть рідкісні проблеми з тимчасовим обмеженням. Модулі ES6 - хороший спосіб зробити це, але є багато бібліотек, які також можуть бути використані.
кмкемп

26

Чи проводились ваші тести на особистому комп’ютері чи на веб-сервері? Це порожня сторінка чи це складна онлайн-система із зображеннями, базами даних тощо? Ваші сценарії виконують просту дію наведення курсору чи вони є основним компонентом того, як ваш веб-сайт відображає та взаємодіє з користувачем? Тут слід враховувати кілька речей, і актуальність цих рекомендацій майже завжди стає правилами, коли ви наважуєтесь на розробку веб-сайтів високого калібру.

Метою правила "розмістити таблиці стилів у верхній частині та сценарії внизу" є те, що, як правило, це найкращий спосіб досягти оптимального прогресивного відображення , що є критичним для роботи користувача.

Все інше: якщо ваш тест є дійсним, і ви справді даєте результати всупереч популярним правилам, насправді це не дивно. Кожен веб-сайт (і все, що потрібно для того, щоб вся справа з’явилася на екрані користувача) відрізняється, і Інтернет постійно розвивається.


1
Я ціную точку, яку ви робите жирним шрифтом, але ОП говорить про те, що трапляється, коли ви змінюєте порядок, як вгорі, так і внизу.
nnnnnn

1
Таким чином, "припускаючи [його] тест справедливий".
скіппр

21

Я включаю файли CSS перед Javascript з іншої причини.

Якщо моєму Javascript потрібно зробити динамічне розмір якогось елемента сторінки (для тих кутових випадків, коли CSS справді є основним ззаду), то завантаження CSS після того, як JS перейде в дію, може призвести до перегонових умов, де елемент буде змінено до стилів CSS застосовуються, і, таким чином, виглядає дивно, коли стилі нарешті запускаються. Якщо я заздалегідь завантажую CSS, я можу гарантувати, що все працює у запланованому порядку і що остаточний макет - це те, яким я хочу його бути.


2
це перерветься один день у деякому браузері. Я не здогадуюсь.
jcolebrand

1
jcolebrand: Так, я думаю, що не пив достатньо кави, коли писав це. (З ретроспективою, я думаю, важливі речі полягають у тому, щоб уникнути динамічного завантаження CSS та розміщення JS всередині domReady події, якщо вам потрібно зробити динамічний розмір)
hugomg

Сценарії не повинні змінювати жодне відображення. Це робота CSS. HTML = вміст, CSS = Як відображати вміст, javascript динамічно змінювати вміст. Також js повинен діяти лише після (або під час), коли DOMContentLoaded буде звільнений у деяких незначних, але дуже конкретних ситуаціях.
brunoais

@brunoais: Деякі макети можна створити лише за допомогою Javascript. Наприклад, все, що потрібно динамічно змінити розмір, необхідно робити через Javascript, а деякі речі (наприклад, розмір 100% - 20 пікселів) потребують Javascript, щоб зробити його портативно в старих браузерах.
хугомг

@missingno У будь-яких випадках просто використовуйте подію DOMContentLoaded. Але я розумію, що ти маєш на увазі. (Дурний IE!)
бруноа

10

Чи рекомендується включати CSS перед JavaScript недійсним?

Не якщо ви ставитесь до цього як просто до рекомендації. Але якщо ви ставитесь до цього як до жорсткого і швидкого правила? Так, це недійсно.

Від https://developer.mozilla.org/en-US/docs/Web/Reference/Events/DOMContentLoaded

Склад таблиці завантажує виконання сценарію, тому якщо у вас є сторінка <script> після того, як <link rel="stylesheet" ...>сторінка не завершить розбір - і DOMContentLoaded не запуститься - до завантаження таблиці стилів.

Видається, що вам потрібно знати, на що покладається кожен скрипт, і переконатися, що виконання сценарію затримується до моменту завершення події правильного завершення. Якщо сценарій покладається тільки на DOM, він може відновитись у випадковому / domcontentloaded, якщо він покладається на завантажувані зображення або таблиці стилів, які застосовуються, то, якщо я прочитав вищезазначене посилання правильно, цей код повинен бути відкладений до події завантаження.

Я не думаю, що один розмір шкарпетки підходить усім, хоча саме так вони продаються, і я знаю, що один розмір взуття підходить не всім. Я не думаю, що є остаточна відповідь, на яку потрібно завантажити спочатку, стилі чи сценарій. Це швидше за кожним випадком вирішувати питання про те, що потрібно завантажувати в якому порядку і що можна відкласти до цього часу, щоб не знаходитись на "критичному шляху".

Щоб поговорити з спостерігачем, який прокоментував, що краще затримати можливість взаємодії користувачів, поки аркуш не стане гарним. Там багато вас, і ви дратуєте своїх колег, які відчувають навпаки. Вони завітали на сайт для досягнення мети, а затримки щодо їх здатності взаємодіяти з сайтом під час очікування речей, які не мають значення для завершення завантаження, дуже неприємні. Я не кажу, що ви помиляєтесь, лише щоб ви усвідомлювали, що існує ще одна фракція, яка не поділяє ваш пріоритет.

Це питання стосується особливо всіх оголошень, розміщених на веб-сайтах. Мені б сподобалося, якби автори веб-сайтів надавали лише диски-заповнювачі для вмісту реклами та переконувались, що їх сайт завантажений та інтерактивний, перш ніж вводити рекламу у події завантаження. Навіть тоді я хотів би бачити рекламу, завантажену серійно, а не всі одразу, оскільки вони впливають на мою здатність навіть прокручувати вміст сайту, поки завантажуються роздуті оголошення. Але це лише одна точка зору.

  • Знайте своїх користувачів і що вони цінують.
  • Знайте своїх користувачів та те, яке середовище перегляду вони використовують.
  • Знайте, що робить кожен файл та які його передумови. Здійснення роботи все матиме перевагу перед швидкістю та симпатичністю.
  • Використовуйте інструменти, які показують мережевий часовий рядок під час розробки.
  • Тестуйте в кожному з середовищ, якими користуються ваші користувачі. Може знадобитися динамічно (на стороні сервера під час створення сторінки) змінювати порядок завантаження на основі середовища користувача.
  • Коли ви сумніваєтесь, змініть порядок і виміряйте ще раз.
  • Можливо, що змішування стилів та сценаріїв у порядку завантаження буде оптимальним; не всі то одне, то все інше.
  • Експериментуйте не лише в тому, який порядок завантаження файлів, але і де. Голова? В Тіло? Після Тіла? DOM готовий / завантажений? Завантажений?
  • Розгляньте параметри асинхронізації та відстрочки, коли це доречно, щоб зменшити чисту затримку, яку користувач зазнає, перш ніж мати можливість взаємодіяти зі сторінкою. Тест, щоб визначити, чи допомагають вони чи шкодять.
  • Завжди знайдеться компроміс, який слід враховувати при оцінці оптимального порядку завантаження. Гарненький проти чуйний, будучи лише одним.

1
Пов'язана стаття більше не стверджує, що "Стилі таблиці завантажують виконання сценарію блоку". Це вже не правда?
Грег

@Greg - Це все-таки правда. Сценарії повинні мати можливість запитувати атрибути DOM .style, тому таблиці стилів все ще блокують виконання сценарію. Вони можуть не блокувати завантаження сценарію , якщо вони розумні, але вони заблокують події script.onLoad.
Джиммі Брек-Маккі

10

Оновлено 2017-12-16

Я не був впевнений у тестах на ОП. Я вирішив трохи експериментувати і в кінцевому підсумку перекинув деякі міфи.

Синхронний <script src...>блокує завантаження під ним ресурсів, поки не буде завантажено та виконано

Це вже не так . Погляньте на водоспад, створений 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>

Інспектор сітки Chrome -> водоспад

<link rel=stylesheet> не блокує завантаження та виконання скриптів під ним

Це неправильно . Таблиця стилів не блокуватиме завантаження , але він буде блокувати виконання скрипта ( мало пояснень тут ). Перегляньте діаграму ефективності, сформовану 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>

Інструменти для розробників Chrome -> продуктивність


Маючи на увазі вищесказане, результати ОП можна пояснити так:

Перший CSS:

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

JS Перший:

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

Ось чому document.write () - одна з найгірших ідей, що коли-небудь робилися для 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/… Чому те саме припущення не застосовується у випадку спочатку JS? Для мене це не має великого сенсу, замовлення виконаного JS нічого не говорить про його призначення.
Торстен Шьонінг

4

Я не точно впевнений, як тестування "візуалізує" час використання вашого сценарію Java. Однак врахуйте це

Одна сторінка на вашому веб-сайті розміром 50 тис. Дол., Що нерозумно. Користувач знаходиться на східному узбережжі, а ваш сервер - на західному. MTU, безумовно, не становить 10 к., Тому буде кілька поїздок туди і назад. Отримати вашу сторінку та таблиці стилів може зайняти 1/2 секунди. Зазвичай (для мене) javascript (через jquery плагін і подібні) набагато більше, ніж CSS. Існує також те, що відбувається, коли ваше інтернет-з'єднання задихається на середині сторінки, але дозволяє ігнорувати це (це трапляється зі мною періодично, і я вважаю, що css робить, але я не впевнений на 100%).

Оскільки css знаходиться в голові, для його отримання можуть бути додаткові з'єднання, а це означає, що потенційно він може закінчитися до того, як ця сторінка стане. У будь-якому разі під час введення залишку сторінки, а файлів javascript (що набагато більше байтів) сторінка не стилізована, що робить сайт / з'єднання повільним.

ВЖЕ, якщо інтерпретатор JS відмовляється запускатись, поки CSS не буде виконано час, необхідний для завантаження коду javascript, особливо коли далеко від сервера врізається час CSS, що зробить сайт не дуже гарним.

Це невелика оптимізація, але ось причина.


1
сервер знаходиться на східному узбережжі, fwiw. Ви також, мабуть, не знаєте про те, що зараз вони використовують CDN.
jcolebrand

3

Ось підсумок всіх основних відповідей вище (а може, нижче пізніше :)

Для сучасних браузерів поставте css куди завгодно. Вони проаналізують ваш html-файл (який вони називають спекулятивним розбором ) і почнуть завантажувати css паралельно з html-розбором.

Для старих браузерів продовжуйте ставити css зверху (якщо ви не хочете спочатку показувати голу, але інтерактивну сторінку).

Для всіх браузерів поставте JavaScript якомога далі на сторінку, оскільки це зупинить розбір вашого html. Переважно завантажуйте його асинхронно (тобто, виклик Ajax)

Існують також деякі експериментальні результати для конкретного випадку, який стверджує, що встановлення javascript спочатку (на відміну від традиційної мудрості ставити CSS на перше місце) дає кращі показники, але для цього немає логічних міркувань і не вистачає перевірки щодо широкої застосовності, тому ви можете поки це ігноруйте.

Отже, щоб відповісти на питання: Так. Рекомендація включати CSS до JS недійсна для сучасних браузерів. Розмістіть CSS куди завгодно, а JS покладіть до кінця, наскільки це можливо.


1

Стів Суудерс вже дав остаточну відповідь, але ...

Цікаво, чи існує проблема як з оригінальним тестом Сема, так і з повторенням його Джоша.

Здається, обидва тести були виконані на низьких затримкових з'єднаннях, коли налаштування TCP-з'єднання матиме тривіальну вартість.

Як це впливає на результат тесту. Я не впевнений, і я хотів би подивитися на водоспади для тестів на "звичайне" латентне з'єднання, але ...

Перший завантажений файл повинен отримати з'єднання, яке використовується для html-сторінки, а другий завантажений файл отримає нове з'єднання. (Промивання на ранніх змінах динамічно, але це не робиться тут)

У нових веб-переглядачах друге TCP-з'єднання відкривається спекулятивно, тому накладні зв’язки зменшуються / відпадають, у старих браузерах це не відповідає дійсності, а для другого з'єднання відкриється накладні витрати.

Досить, як / якщо це вплине на результат тестів, я не впевнений.


не слід, якщо у вас є конвеєр, який надзвичайно рідкісний, ви навряд чи зможете зменшити налаштування з'єднання ... погодьтесь, тест слід повторити з низькою затримкою
Сем Сафрон

Якщо ви подивитесь на цей водоспад, то можна побачити, де Chrome спекулятивно відкриває друге з'єднання, перш ніж це потрібно webpagetest.org/result/… (IE9 робить те саме) ... Я думав, нормальна затримка для цілей TCP, а не низька - який сорт навколишнього середовища тест робився в?
Енді Девіс

2
Re: "Стів Суудерс вже дав остаточну відповідь, але ..." Справа з розвитком веб-сторінок полягає в тому, що немає остаточних відповідей. :) Існує 3-4 способи завантаження сценаріїв, і все змінюється. Справжній правильний смисловий насправді повинен був сказати Стіву "Покласти CSS перед синхронним JavaScript" Інакше люди помиляються, узагальнюючи, як це правило для всіх сценаріїв ...
hexalys

Так, але більшість людей просто включають сценарії синхронно, тому порада Стіва корисна непосвяченим.
Енді Девіс

1

Я думаю, що це неправда для всіх випадків. Тому що css буде завантажувати паралельно, але js cant. Розглянемо той самий випадок,

Замість того, щоб мати один css, візьміть 2 або 3 файли css і спробуйте ці способи,

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

Я впевнений, що css..css..js дасть кращий результат, ніж усі інші.


0

Ми маємо пам’ятати, що нові браузери працювали над своїми движками Javascript, їх аналізаторами тощо, оптимізуючи загальні проблеми з кодом та розміткою таким чином, що проблеми, що виникають у старовинних браузерах, таких як <= IE8, вже не актуальні, не тільки для що стосується розмітки, але також використання змінних JavaScript, селекторів елементів і т. д. Я можу побачити в не так далекому майбутньому ситуацію, коли технологія досягла такої точки, коли продуктивність вже не є проблемою.


Продуктивність завжди є проблемою. Я майже ігнорую, що існують браузери, які не дотримуються специфікації. Я просто готую свій код таким чином, що ті, які слідкують за специфікацією, працюють на повній швидкості, а інші я просто роблю так, щоб він працював. Так, наприклад, якщо це просто працює в IE8, все нормально.
brunoais

-5

Особисто я б не робив надто великого акценту на такій «народній мудрості». Те, що можливо було правдою в минулому, цілком може бути істинним. Я б припустив, що всі операції, пов'язані з інтерпретацією та візуалізацією веб-сторінки, є повністю асинхронними ("видобування" чогось і "дію на нього" - це дві абсолютно різні речі, які можуть оброблятися різними потоками тощо ), і у будь-якому випадку повністю поза вашим контролем або вашим занепокоєнням.

Я б помістив посилання CSS у "головну" частину документа разом із будь-якими посиланнями на зовнішні сценарії. (Деякі сценарії можуть вимагати розміщення в тілі, і якщо так, зобов'язуйте їх.)

Крім цього ... якщо ви помітите, що "в цьому / тому браузері це здається швидше / повільніше, ніж це", трактуйте це спостереження як цікаве, але неактуальне цікавість, і не дозволяйте йому впливати на ваші дизайнерські рішення. Занадто багато речей змінюється занадто швидко. (Хто-небудь хоче поставити будь-які ставки на те, скільки хвилин пройде, перш ніж команда Firefox вийде з черговим проміжним випуском свого продукту? Так, мені також.)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.