Должен ли 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-включений?

Понятно, что мы могли бы добавить асинхронность или использовать 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 раз в 3 основных браузерах.

Результаты

Во-первых, с задержкой файла 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 на 500 мс вместо 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>должен ли s идти перед <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%)
  • Safari 4 (99%)
  • Опера 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 не поддерживает спекулятивный анализ. Я подозреваю, что он может быть отключен из-за ограничений процессора, памяти и / или сети, присущих мобильным устройствам.

Код

Прости за разгильдяйство - это был 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 был jquery-1.7.1.min.js


137
это фантастический ответ, спасибо за использование науки! В соответствии с вашим результатом «в современных браузерах, похоже, что ссылки на CSS сначала никогда не дают выигрыша в производительности» , я думаю, что ответ на вопрос « да» , старый совет CSS сначала явно недействителен.
Джефф Этвуд

Что касается обновления @ josh3736 об обратном на мобильном телефоне ... это пример того, чтобы не прыгать из-за этого существенного изменения. Мне было бы любопытно, как ведут себя другие мобильные браузеры (webkit, gecko, presto, trident и т. Д.), Поскольку производительность в мобильных устройствах часто важнее.
scunliffe

1
Вам также следует попробовать добавить некоторую медлительность в распечатку css / js, чтобы имитировать скорости медленного сервера.
Кир

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 интересно создавать примеры . Например, на этой странице есть сценарий в заголовке, поэтому вся страница остается пустой, пока она не завершит загрузку. Однако, если мы переместим скрипт в конец блока BODY, будет отображен заголовок страницы, поскольку эти элементы DOM находятся над тегом SCRIPT, как вы можете видеть на этой странице .


10
Уважаемый Стив побил меня ответом, но я добавлю статью, относящуюся к тому, что он упоминает: stevesouders.com/blog/2009/04/27/…
Хуан Пабло Буритика

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 (например, ширина или высота div), не будет загружен правильно. Кажется, что при неправильном порядке загрузки правильные свойства «иногда» известны Javascript (возможно, это вызвано состоянием гонки?). Этот эффект кажется больше или меньше в зависимости от используемого браузера.


2
Как бы вы гарантировали, что все CSS были загружены до выполнения javascript? Ты можешь? или ваш javascript должен быть достаточно надежным, чтобы справиться с ситуацией, когда стили не обязательно загружаются.
Джоннио

@Jonnio Если у вашего JS есть зависимость, вы должны сделать эту зависимость явной. В противном случае у вас всегда будут редкие проблемы со временем. Модули ES6 - хороший способ сделать это, но есть много библиотек, которые также могут быть использованы.
кмкемп

26

Были ли ваши тесты выполнены на вашем персональном компьютере или на веб-сервере? Это пустая страница, или это сложная онлайн-система с изображениями, базами данных и т. Д.? Ваши сценарии выполняют простое действие при наведении на них, или они являются основным компонентом того, как ваш веб-сайт отображает и взаимодействует с пользователем? Здесь нужно учитывать несколько моментов, и актуальность этих рекомендаций почти всегда становится правилом, когда вы начинаете заниматься веб-разработкой высокого уровня.

Цель правила «размещать таблицы стилей вверху и сценарии внизу» состоит в том, что, в общем, это лучший способ добиться оптимального прогрессивного рендеринга , что очень важно для взаимодействия с пользователем.

Кроме всего прочего: если ваш тест действителен, и вы действительно производите результаты, противоречащие популярным правилам, то это неудивительно. Каждый веб-сайт (и все, что нужно для того, чтобы все это отображалось на экране пользователя) отличается, и Интернет постоянно развивается.


1
Я ценю то, что вы подчеркиваете жирным шрифтом, но ОП рассказывает о том, что происходит, когда вы меняете порядок как сверху, так и снизу.
nnnnnn

1
Таким образом, «предполагая, что его тест действителен».
Skippr

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 был выполнен переносимым в старых браузерах.
hugomg

@missingno В этих случаях, в любом случае, просто используйте событие DOMContentLoaded. Но я понимаю, что вы имеете в виду. (Глупый IE!)
brunoais

10

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

Нет, если вы рассматриваете это как просто рекомендацию. Но если вы относитесь к этому как к жесткому и быстрому правилу? Да, это недействительно.

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

Таблица стилей загружает выполнение сценария блока, поэтому, если у вас есть <script> после, <link rel="stylesheet" ...>страница не завершит синтаксический анализ - и DOMContentLoaded не будет запускаться - до тех пор, пока таблица стилей не будет загружена.

Похоже, вам нужно знать, на что опирается каждый сценарий, и убедиться, что выполнение сценария отложено до момента правильного события завершения. Если скрипт использует только DOM, он может возобновить работу в ondomready / domcontentloaded, если он полагается на загружаемые изображения или применяемые таблицы стилей, тогда, если я правильно прочитал приведенную выше ссылку, этот код должен быть отложен до события onload.

Я не думаю, что один размер носка подходит всем, хотя так они продаются, и я знаю, что один размер обуви подходит не всем. Я не думаю, что есть определенный ответ, на который нужно сначала загрузить стили или скрипт. Это в большей степени индивидуальное решение о том, что должно быть загружено в каком порядке и что может быть отложено до тех пор, пока оно не окажется на «критическом пути».

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

Этот вопрос особенно относится ко всем объявлениям, размещаемым на веб-сайтах. Я был бы рад, если бы авторы сайта создавали только элементы-заполнители для содержания рекламы и следили за тем, чтобы их сайт был загружен и интерактивен, прежде чем вставлять рекламу в событие загрузки. Даже тогда я хотел бы видеть рекламу, загружаемую поочередно, а не все сразу, потому что они влияют на мою способность даже прокручивать контент сайта во время загрузки раздутых объявлений. Но это точка зрения только одного человека.

  • Знайте своих пользователей и что они ценят.
  • Знайте своих пользователей и какую среду просмотра они используют.
  • Знайте, что делает каждый файл, и каковы его предпосылки. Заставить все работать будет иметь приоритет над скоростью и красотой.
  • Используйте инструменты, которые показывают вам график времени сети при разработке.
  • Протестируйте в каждой среде, которую используют ваши пользователи. Возможно, потребуется динамически (на стороне сервера, при создании страницы) изменить порядок загрузки в зависимости от среды пользователя.
  • В случае сомнений измените порядок и повторите измерения.
  • Возможно, что сочетание стилей и сценариев в порядке загрузки будет оптимальным; не все одно потом все другое.
  • Экспериментируйте не только в каком порядке загружать файлы, но и где. Глава? В теле? После тела? ДОМ готов / загружен? Загруженный?
  • При необходимости рассмотрите варианты асинхронности и отсрочки, чтобы уменьшить чистую задержку, с которой пользователь столкнется, прежде чем сможет взаимодействовать со страницей. Тест, чтобы определить, помогают ли они или вредят.
  • Всегда будут компромиссы, которые следует учитывать при оценке оптимального порядка загрузки. Довольно против Отзывчивого бытия только один.

1
В связанной статье больше не утверждается "Таблица стилей загружает выполнение скрипта блока". Это больше не правда?
Грег

@ Грег - Это все еще правда. Сценарии должны иметь возможность запрашивать атрибуты 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>

Инспектор хромированной сетки -> водопад

<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 First:

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:                                                                                                                                            

Вот почему 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
Сервер находится на восточном побережье. Вы также, очевидно, не знаете о том, что они теперь используют 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 не могу. Рассмотрим для того же случая,

Вместо того, чтобы иметь один 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.