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

762

В бесчисленных местах онлайн я видел рекомендацию включать CSS до JavaScript. Обоснование обычно этой формы:

Когда дело доходит до заказа CSS и JavaScript, вы хотите, чтобы ваш CSS прийти первым. Причина в том, что поток рендеринга имеет все которая должна отображать страницу. Если JavaScript включает, прежде всего, движок JavaScript должен разбирать все это до переходя к следующему набору ресурсов. Это означает, что рендеринг нить не может полностью показать страницу, так как она не имеет всех стилей, в которых он нуждается.

Мое фактическое тестирование показывает что-то совсем другое:

Мой тестовый жгут

Я использую следующий Ruby script для генерации определенных задержек для различных ресурсов:

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 секунды для рендеринга:

Изображение 95

Когда я включаю JavaScript сначала, страница занимает 1.4 секунды для рендеринга:

Изображение 96

Я получаю аналогичные результаты в Chrome, Firefox и Internet Explorer. В Opera, однако, порядок просто не имеет значения.

Что, по-видимому, происходит, так это то, что интерпретатор JavaScript отказывается запускать, пока не будет загружен весь CSS. Таким образом, кажется, что включение JavaScript в первую очередь более эффективно, так как поток JavaScript получает больше времени выполнения.

Мне что-то не хватает, рекомендуется ли размещать CSS-код до того, как JavaScript включится неверно?

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

  • 117
    1511 против 1422 статистически значимая разница? Это 6 процентов. Общий порог для заметной разницы в производительности у человека составляет около 20 процентов.
  • 14
    Дело в том, что переупорядочение устраняет эту произвольную задержку, вы можете установить задержку на что угодно, это просто демонстрация проблемы.
Показать ещё 7 комментариев
Теги:
performance

13 ответов

653
Лучший ответ

Это очень интересный вопрос. Я всегда ставил свой CSS <link href="..."> перед моим JS <script src="...">, потому что "я читал один раз, чтобы это было лучше". Итак, вы правы; пришло время провести какое-то настоящее исследование!

Я установил свой собственный тестовый жгут в Node (код ниже). В принципе, я:

  • Убедитесь, что HTTP-кеширование не было, поэтому браузер должен будет выполнять полную загрузку каждый раз при загрузке страницы.
  • Чтобы имитировать реальность, я включил jQuery и H5BP CSS (так что там было достойное количество script/CSS для разбора)
  • Настройте две страницы - одну с CSS до script, одну с CSS после script.
  • Записано, сколько времени потребовалось для внешнего script в <head> для выполнения
  • Записано, сколько времени потребовалось для встроенного script в <body>, что аналогично DOMReady.
  • Отложить отправку CSS и/или script в браузер на 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> идти до <link> в <head>.

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

Учитывая, что привязка к CSS последнему не ухудшает производительность, но может обеспечить выигрыш при определенных обстоятельствах, следует ссылаться на внешние таблицы стилей после того, как вы ссылаетесь на внешние скрипты только на настольных браузерах, если производительность старые браузеры не являются проблемой. Читайте дальше для мобильной ситуации.

Почему?

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

Следовательно, широко повторяющийся совет поместить таблицы стилей сначала – они будут загружаться первыми, и первая загрузка script для загрузки может быть загружена параллельно.

Однако современные браузеры (включая все браузеры, которые я тестировал выше) внедрили умозрительный анализ, где браузер "смотрит вперед" в HTML и начинает загрузку ресурсов до загрузки и выполнения скриптов.

В старых браузерах без спекулятивного разбора статические скрипты сначала влияют на производительность, так как они не будут загружаться параллельно.

Поддержка браузера

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

  • Chrome 1 (WebKit 525) (100%)
  • IE 8 (75%)
  • Firefox 3.5 (96%)
  • Safari 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, похоже, не поддерживает спекулятивный синтаксический анализ. Я подозреваю, что он может быть отключен из-за ограничений по ЦП, памяти и/или сети, присущих мобильным устройствам.

Код

Простите неряшливость – это 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

  • 134
    это фантастический ответ, спасибо за использование науки! Согласно вашему результату «в современных браузерах, похоже, что ссылки на CSS сначала никогда не дают прирост производительности» , я думаю, что ответ на вопрос « да» , старый совет CSS сначала явно недействителен.
  • 8
    Я не могу дождаться того дня, когда мне понадобится только поддержка современных браузеров! Я был бы рад, если бы это было так!
Показать ещё 11 комментариев
289

Есть две основные причины, по которым CSS стоит перед JavaScript.

  • Старые браузеры (Internet Explorer 6-7, Firefox 2 и т.д.) блокируют все последующие загрузки, когда они начнут загружать script. Поэтому, если у вас есть a.js, за которым следует b.css, они загружаются последовательно: сначала a, затем b. Если у вас есть b.css, за которым следует a.js, они загружаются параллельно, поэтому страница загружается быстрее.

  • Ничего не отображается до тех пор, пока не будут загружены все таблицы стилей - это верно во всех браузерах. Скрипты разные - они блокируют рендеринг всех элементов DOM, которые находятся ниже тега script на странице. Если вы поместите свои скрипты в HEAD, значит, вся страница заблокирована от рендеринга, пока не будут загружены все таблицы стилей и все сценарии. Хотя имеет смысл блокировать весь рендеринг для таблиц стилей (так что вы получаете правильное стилирование в первый раз и избегаете вспышки неокрашенного содержимого FOUC), нет смысла блокировать рендеринг всей страницы для скриптов. Часто скрипты не влияют ни на какие элементы DOM, ни на часть элементов DOM. Лучше всего загружать скрипты как можно ниже на странице, или даже лучше загружать их асинхронно.

Приятно создавать примеры с Cuzillion. Например, эта страница имеет script в HEAD, поэтому вся страница пуста, пока она не загрузится. Однако, если мы переместим script в конец блока BODY, заголовок страницы отобразится, поскольку эти элементы DOM произойдут над тегом script, как вы можете видеть на на этой странице.

  • 9
    Уважаемый Стив опередил меня в ответ, но я добавлю статью, относящуюся к тому, что он упоминает: stevesouders.com/blog/2009/04/27/…
  • 4
    Посмотрите, какие браузеры поддерживают атрибут async , который Стив рекомендует здесь, когда он говорит: «Еще лучше загрузить их асинхронно» - stackoverflow.com/questions/1834077/…
Показать ещё 6 комментариев
36

Я бы не особо подчеркивал результаты, которые у вас есть, я считаю, что это субъективно, но у меня есть причина объяснить вам, что лучше поставить CSS до js.

Во время загрузки вашего сайта есть два сценария, которые вы увидите:

CASE 1: белый экран > неэкранированный веб-сайт > стиль веб-сайтa > взаимодействие > стиль и интерактивный веб-сайт

CASE 2: белый экран > неизданный веб-сайт > взаимодействие > стиль веб-сайтa > стиль и интерактивный веб-сайт


Я, честно говоря, не могу представить, чтобы кто-то выбирал Case 2. Это означало бы, что посетители, использующие медленные интернет-соединения, столкнутся с неустановленным веб-сайтом, который позволяет им взаимодействовать с ним с помощью Javascript (так как это уже загружено). Кроме того, количество времени, затрачиваемое на незакрепленный веб-сайт, будет максимизировано таким образом. Зачем кому-то это нужно?

Он также работает лучше, чем состояния jQuery

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

Когда файлы загружаются в неправильном порядке (сначала JS, затем CSS), любой Javascript-код, основанный на свойствах, заданных в файлах CSS (например, ширина или высота div), не будет загружен правильно. Похоже, что с неправильным порядком загрузки правильные свойства "иногда" известны Javascript (возможно, это вызвано состоянием гонки?). Этот эффект кажется большим или меньшим в зависимости от используемого браузера.

  • 2
    Как бы вы гарантировали, что все CSS были загружены перед выполнением javascript? Ты можешь? или ваш javascript должен быть достаточно надежным, чтобы справиться с ситуацией, когда стили не обязательно загружаются.
  • 0
    @Jonnio Если у вашего JS есть зависимость, вы должны сделать эту зависимость явной. В противном случае у вас всегда будут редкие проблемы со временем. Модули ES6 - хороший способ сделать это, но есть много библиотек, которые также могут быть использованы.
22

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

Цель правила "put stylesheets at the top и scripts the bottom" заключается в том, что в целом это лучший способ добиться оптимального прогрессивного рендеринга, который имеет решающее значение для пользователя.

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

  • 1
    Я ценю то, что вы подчеркиваете жирным шрифтом, но ОП рассказывает о том, что происходит, когда вы меняете порядок как сверху, так и снизу.
  • 1
    Таким образом, «предполагая, что его тест действителен».
19

Я включаю файлы CSS перед Javascript по другой причине.

Если моему Javascript необходимо выполнить динамическую калибровку некоторого элемента страницы (для тех угловых случаев, когда CSS действительно является основным в обратном направлении), тогда загрузка CSS после того, как JS русифицирует, может привести к условиям гонки, где элемент изменяется прежде чем стили CSS будут применены и, таким образом, выглядят странно, когда стили наконец начнутся. Если я загружаю CSS заранее, я могу гарантировать, что все будет выполняться в заданном порядке и что окончательный макет - это то, что я хочу.

  • 1
    это сломает один день в каком-то браузере. Я не догадываюсь.
  • 0
    jcolebrand: Да, я думаю, что не выпил достаточно кофе, когда писал это. (В ретроспективе, я думаю, важнее всего избежать динамической загрузки CSS и поместить JS в событие domReady, если вам нужно выполнить динамическое изменение размеров)
Показать ещё 4 комментария
7

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

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

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

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

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

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

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

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

  • Знайте своих пользователей и то, что они ценят.
  • Знайте своих пользователей и их среду просмотра.
  • Знайте, что делает каждый файл, и каковы его предварительные требования. Выполнение всех работ будет иметь приоритет над скоростью и красивой.
  • Используйте инструменты, показывающие сетевую временную линию при разработке.
  • Тест в каждой среде, которую используют пользователи. Может потребоваться динамическое (серверная сторона при создании страницы) изменить порядок загрузки в зависимости от среды пользователя.
  • В случае сомнений измените порядок и меру снова.
  • Возможно, что смешивание стилей и скриптов в порядке загрузки будет оптимальным; не все из них, а затем все остальные.
  • Экспериментируйте не только с каким заказом для загрузки файлов, но и где. Глава? В теле? После тела? DOM готов/загружен? Загруженный?
  • Рассмотрите варианты асинхронного и отсрочки, когда это необходимо, чтобы уменьшить чистую задержку, которую пользователь испытает, прежде чем сможет взаимодействовать со страницей. Тест, чтобы определить, помогают ли они или причиняют боль.
  • При оценке оптимального порядка загрузки всегда учитываются компромиссы. Превосходное и отзывчивое - всего лишь одно.
  • 1
    В связанной статье больше не утверждается "Таблица стилей загружает выполнение скрипта блока". Это больше не правда?
  • 0
    @ Грег - Это все еще правда. Сценарии должны иметь возможность запрашивать атрибуты DOM .style, поэтому таблицы стилей по-прежнему блокируют выполнение сценариев. Они могут не блокировать загрузку скрипта, если они умные, но они будут блокировать события script.onLoad.
4

Я не совсем уверен, как ваше тестирование "рендеринга" при использовании java script. Однако рассмотрим этот

Одна страница на вашем сайте - 50 тыс., что не является необоснованным. Пользователь находится на восточном побережье, а ваш сервер находится на западе. MTU определенно не 10k, поэтому будет несколько поездок туда и обратно. Для получения вашей страницы и таблиц стилей может потребоваться 1/2 секунды. Обычно (для меня) javascript (через плагин jquery и т.д.) Гораздо больше, чем CSS. Theres также, что происходит, когда ваше подключение к Интернету задыхается на полпути на странице, но позволяет игнорировать это (иногда это происходит со мной, и я считаю, что css оказывает, но я не уверен на 100%).

Так как css находится в голове, могут быть дополнительные подключения, чтобы получить его, что означает, что он может закончить до того, как страница сделает. В любом случае во время типа оставшейся части страницы и файлов javascript (что намного больше байтов) страница неустановлена, что делает сайт/соединение медленным.

ДАЖЕ ЕСЛИ интерпретатор JS отказывается начинать до тех пор, пока CSS не будет выполнен, чтобы загрузить код javascript, особенно если далеко от сервера вырезается время css, что сделает сайт не очень красивым.

Небольшая оптимизация, но для этого и есть причина.

  • 1
    Сервер находится на восточном побережье. Вы также, очевидно, не знаете о том, что они сейчас используют CDN.
2

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

Я не был уверен в тестах в OP. Я решил немного поэкспериментировать и в конечном итоге перебор некоторых мифов.

Синхронный <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>

Изображение 2215

<link rel=stylesheet> не будет блокировать загрузку и выполнение скрипты под ним

Это неверно. Таблица стилей не будет блокировать загрузку, но она заблокирует выполнение script (небольшое объяснение здесь). Посмотрите диаграмму производительности, созданную 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>

Изображение 2216


Учитывая вышеизложенное, результаты в OP можно объяснить следующим образом:

Сначала 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:                                                                                                                                            ◆
  • 0
    Вот почему document.write () - одна из худших идей, когда-либо созданных для HTMLDOM.
  • 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 ничего не говорит о его назначении.
1

Вот краткое изложение всех основных ответов выше (или, возможно, ниже:)

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

Для старых браузеров сначала ставьте css сверху (если вы не хотите сначала показывать голую, но интерактивную страницу).

Для всех браузеров поместите javascript как можно дальше на страницу, так как он остановит разбор вашего html. Предпочтительно загружать его асинхронно (т.е. Вызов ajax)

Есть также некоторые экспериментальные результаты для конкретного случая, в котором утверждается, что сначала положить javascript (в отличие от традиционной мудрости ввода CSS) дает более высокую производительность, но для этого нет логических аргументов, и отсутствует проверка относительно широко распространенной применимости, поэтому вы можете игнорировать его пока.

Итак, чтобы ответить на вопрос: Да. Рекомендация включить CSS перед JS недействительна для современных браузеров. Поместите CSS везде, где хотите, и поставите JS ближе к концу, насколько это возможно.

1

Я думаю, что это не будет верно для всех случаев. Потому что css будет загружать параллельно, но js can not. Рассмотрим для одного и того же случая,

Вместо того, чтобы иметь один css, возьмите 2 или 3 файла css и попробуйте это,

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

Я уверен, что css..css..js даст лучший результат, чем все остальные.

1
Стив Соудерс уже дал окончательный ответ, но...

Интересно, есть ли проблема с исходным тестом Sam и повторением Josh.

Оба теста, как представляется, выполнялись в соединениях с низкой задержкой, когда настройка TCP-соединения будет иметь тривиальные затраты.

Как это влияет на результат теста, я не уверен, и я бы хотел посмотреть на водопады для тестов по "нормальному" соединению с задержкой, но...

Первый загруженный файл должен получить соединение, используемое для html-страницы, а второй загруженный файл получит новое соединение. (Промывка рано меняет эту динамику, но это не делается здесь)

В новых браузерах второе TCP-соединение открывается созерцательно, поэтому накладные расходы на соединение снижаются/уходят, в старых браузерах это неверно, а второе соединение будет иметь накладные расходы при открытии.

Довольно, как это сделать, если это влияет на результаты тестов, я не уверен.

  • 0
    не следуйте, если у вас нет конвейерной передачи, что невероятно редко, вы вряд ли уменьшите настройку соединения ... согласитесь, тест должен быть повторен при низкой задержке
  • 0
    Если вы посмотрите на этот водопад, то увидите, что Chrome спекулятивно открывает второе соединение, прежде чем оно понадобится. Webpagetest.org/result/… (IE9 делает то же самое) ... Я думал, что обычная задержка для целей TCP, а не низкая - какого рода окружающей среды был проведен тест?
Показать ещё 2 комментария
0

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

  • 0
    Производительность - это всегда проблема. Я просто почти игнорирую существование браузеров, которые не соответствуют спецификации. Я просто готовлю свой код так, чтобы те, которые следуют спецификации, работали на полной скорости, а другие, которые я делаю, работали так. Так, например, если он просто работает в IE8, все в порядке.
-5

Лично я бы не стал уделять слишком много внимания такой "народной мудрости". То, что могло быть правдой в прошлом, может быть не совсем верно. Я бы предположил, что все операции, связанные с интерпретацией и рендерингом веб-страницы, полностью асинхронны ( "выборка" и "действие на нее" - это две совершенно разные вещи, которые могут обрабатываться разными потоками и т.д.) И в любом случае полностью вне вашего контроля или вашей озабоченности.

Я бы поставил ссылки CSS в "головной" части документа вместе с любыми ссылками на внешние скрипты. (Некоторые скрипты могут потребовать, чтобы их помещали в тело, и если да, обязывайте их.)

Помимо этого... если вы заметите, что "это кажется более быстрым/медленным, чем это, в этом/этом браузере", рассматривайте это наблюдение как интересное, но неактуальное любопытство и не позволяйте ему влиять на ваши проектные решения. Слишком много слишком сильно меняется. (Кто-нибудь хочет сделать какие-либо ставки на сколько минут будет до того, как команда Firefox выйдет с еще одним промежуточным выпуском своего продукта? Да, я тоже.)

Сообщество Overcoder
Наверх
Меню