Является ли $(document).ready() и CSS готовым?

У меня есть script, выполняющий на $(document).ready(), который должен вертикально выравнивать элемент блока в моем макете. В 90% случаев он работает без проблем. Однако для этого дополнительного 10% происходит одна из двух вещей:

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

  • Центрирование будет полностью испорчено, и элемент блока будет либо сдвинут слишком далеко, либо недостаточно далеко. Похоже, что он пытался подсчитать высоту, но получал неправильные измерения.

Есть ли причина, почему выполнение script в DOM-ready не будет иметь все правильные значения CSS, введенные в DOM еще? (все CSS находится в <head> через <link>).

Кроме того, здесь script, который вызывает проблему (да, это было принято прямо из здесь):

 (function ($) {
    // VERTICALLY ALIGN FUNCTION
    $.fn.vAlign = function() {
      return this.each(function(i) {
        var ah = $(this).height();
        var ph = $(this).parent().height();
        var mh = (ph - ah) / 2;
        $(this).css('margin-top', mh);
      });
    };
  })(jQuery);

Спасибо.

Ответ 1

Из 1.3 примечания к выпуску:

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

В документации ready (fn):

Примечание. Убедитесь, что все таблицы стилей включены перед вашими сценариями (особенно те, которые вызывают функцию готовности). При этом убедитесь, что все свойства элемента правильно определены до начала запуска кода jQuery. Невыполнение этого требования вызовет спорадические проблемы, особенно в браузерах на основе WebKit, таких как Safari.

Обратите внимание, что приведенное выше не относится даже к фактическому рендерингу CSS, поэтому вы можете видеть изменение экрана, когда ready() срабатывает. Но он должен избавить вас от проблем.

На самом деле, мне показалось немного странным, что просто поместить CSS над JS решит все проблемы. CSS загружается асинхронно, поэтому загрузка JS может начинаться и заканчиваться, пока CSS еще загружается. Итак, если вышеописанное решение, тогда выполнение любого JS-кода затем останавливается до тех пор, пока все более ранние запросы не будут завершены?

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

См. JS Bin для некоторые HTML и его результаты (у этого есть 10 секундная задержка), и см. webpagetest.org для его результатов водопада. Это использует некоторые script от Steve Souders cuzillion.com, чтобы имитировать медленные ответы. В водопаде ссылка на resource.cgi - это CSS. Таким образом, в Internet Explorer первый внешний JS начинает загружаться сразу после запроса CSS (но для завершения CSS потребуется еще 10 секунд). Но второй тег <script> не выполняется до завершения загрузки CSS:

<link rel="stylesheet" type="text/css" href=".../a script that delays.cgi" />

<script type="text/javascript" src=".../jquery.min.js"></script> 

<script type="text/javascript"> 
  alert("start after the CSS has fully loaded"); 
  $(document).ready(function() { 
    $("p").addClass("sleepcgi"); 
    alert("ready"); 
  });         
</script> 

Waterfall with a single external JS script

Еще один тест со вторым внешним JS после получения jQuery, показывает, что загрузка второго JS не запускается до загрузки CSS. Здесь первая ссылка на resource.cgi - это CSS, вторая - JS:

Waterfall with two external JS scripts

Перемещение таблицы стилей ниже всех JS действительно показывает, что JS (включая функцию ready) выполняется намного раньше, но даже тогда класс jQuery -приложения, который еще неизвестен, когда JS работает, используется правильно в мои быстрые тесты в Safari и Firefox. Но имеет смысл, что такие вещи, как $(this).height(), будут давать неправильные значения в это время.

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

Последние примечания: поскольку JS Bin включает Google Analytics в каждом script при запуске с голого URL (например, jsbin.com/aqeno, результаты теста фактически изменены JS Bin... Кажется, что вкладка "Вывод" на URL редактирования, например jsbin.com/aqeno/edit не включает в себя дополнительные функции Google Analytics и, конечно же, дает разные результаты, но этот URL-адрес трудно проверить с помощью webpagetest.org. Ссылка на Таблицы стилей Заблокировать загрузки в Firefox и выполнение JavaScript в IE, как указано strager, являются хорошим началом для лучшего понимания, но у меня осталось много вопросов... Также обратите внимание Steve Souders IE8 Parallel script Загрузка, чтобы сделать вещи еще более сложными. (Водопады выше создаются с использованием IE7.)

Возможно, нужно просто поверить в примечания к выпуску и документацию...

Ответ 2

Порядок CSS/JavaScript/JQuery не работает для меня, но следующее:

$(window).load(function() { $('#abc')...} );

Ответ 3

Готовность DOM срабатывает, когда доступны все узлы DOM. Это не имеет ничего общего с CSS. Попробуйте позиционировать стиль раньше или попробуйте загрузить его по-другому.

Ответ 4

Насколько мне известно, готовое событие запускается при загрузке DOM - это означает, что все запросы блокировки (то есть JS) загружены, а дерево DOM полностью выполнено. Состояние готовности в IE зависит от более медленного триггера события (изменение document.readyState и DOMContentLoaded), чем большинство других браузеров, поэтому время зависит также от браузера.

Существование неблокирующих запросов (например, CSS и изображений) полностью асинхронно и не связано с состоянием готовности. Если вы находитесь в положении, где вам нужны такие ресурсы, вам нужно зависеть от старого старого события onload.

Ответ 5

Согласно HTML5, DOMContentLoaded - это простое событие готовности DOM без учета таблиц стилей. Однако, алгоритм синтаксического анализа HTML5 требует, чтобы браузеры откладывали выполнение скриптов, пока не будут загружены все предыдущие таблицы стилей. (DOMContentLoaded и таблицы стилей)

В тесты molily (2010),

  • IE и Firefox заблокировали все последующие действия script до тех пор, пока не будут загружены таблицы стилей
  • Webkit блокирует последующее выполнение только для внешних скриптов (<script src>)
  • Opera не блокировала последующее выполнение для любых скриптов

Все современные браузеры теперь поддерживают DOMContentLoaded (2017), поэтому они могут стандартизировать это поведение к настоящему времени.