Нужна ли «загрузка», когда код находится внизу?

Мне было интересно, необходима ли window.onload = function(){} (или любая другая загрузка, например jQuery $(document).ready();, если код помещен внизу моего <body>?

Или могут быть очень неожиданные побочные эффекты?


person ajax333221    schedule 03.01.2012    source источник


Ответы (3)


Да, могут быть неожиданные последствия. Но нет, это совершенно не обязательно. Время может быть отключено для вещей, которые все еще загружаются, таких как сложные макеты, глубокие структуры DOM, динамический HTML из других скриптов или изображения. Чтобы избежать таких ситуаций, всегда безопаснее обернуть сценарий событием onload.

Вот несколько примеров, демонстрирующих это. Все примеры протестированы на Chrome 17.0.963.12 dev в OS X. Результаты браузера могут отличаться, если не используется onload, что демонстрирует его непредсказуемое поведение. Примеры возвращают fail, если результат отличается от ожидаемого (т. е. того, что указано в вашем проекте), и возвращают success, когда результат соответствует ожидаемому. С onload они всегда возвращают success.

Пример 1

В этом примере код ожидает, что изображение будет иметь определенную ширину. Если код заключен в событие onload, ширина правильная, иначе — нет.

Демонстрация: http://jsfiddle.net/ThinkingStiff/qUWxX/

HTML:

<div id="result"></div>
<img id='image' src="http://thinkingstiff.com/images/matt.jpg" />

Скрипт:

document.getElementById( 'result' ).innerHTML 
    = document.getElementById( 'image' ).offsetWidth == 346 ? 'success': 'fail';

Вы увидите, что для jsFiddle установлено значение «onLoad» в верхнем левом углу страницы, а результат над изображением — success.

введите здесь описание изображения

Измените это на «onDomReady» или «без переноса (тело)»:

введите здесь описание изображениявведите здесь описание изображения

Теперь нажмите «Выполнить» в левом верхнем углу страницы:

введите здесь описание изображения

Результат над изображением теперь будет fail.

Пример 2

Вот еще один пример, в котором не используются изображения. В этом случае встроенный скрипт был добавлен в HTML. Код ожидает, что ширина будет такой, какой она была установлена ​​встроенным скриптом. С onload правильно, без - нет. Используйте те же инструкции, что и раньше для этой демонстрации.

Демонстрация: http://jsfiddle.net/ThinkingStiff/n7GWt/

HTML:

<div id="result"></div>
<div id="style"></div>

<script>
    window.setTimeout( function() { 
        document.getElementById( 'style' ).style.width = '100px'; 
    }, 1 );
</script>

Скрипт:

document.getElementById( 'result' ).innerHTML 
    = document.getElementById( 'style' ).style.width ? 'success' : 'fail';

Пример 3

Вот пример, в котором не используются изображения или Javascript в теле, только CSS. Опять же, результаты различаются между onload и нет.

Демонстрация: http://jsfiddle.net/ThinkingStiff/HN2bH/

CSS:

#style {
    animation:             style 5s infinite;
        -moz-animation:    style 5s infinite;
        -ms-animation:     style 5s infinite;
        -o-animation:      style 5s infinite;
        -webkit-animation: style 5s infinite;
    border: 1px solid black;
    height: 20px;
    width: 100px;    
}

@keyframes             style { 0% { width: 100px; } 100% { width: 500px; } }
    @-moz-keyframes    style { 0% { width: 100px; } 100% { width: 500px; } }
    @-ms-keyframes     style { 0% { width: 100px; } 100% { width: 500px; } }
    @-o-keyframes      style { 0% { width: 100px; } 100% { width: 500px; } }
    @-webkit-keyframes style { 0% { width: 100px; } 100% { width: 500px; } }

HTML:

<div id="result"></div>
<div id="style"></div>

Скрипт:

document.getElementById( 'result' ).innerHTML 
    = document.getElementById( 'style' ).clientWidth > 100 ? 'success' : 'fail';

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

person ThinkingStiff    schedule 03.01.2012
comment
Я не верю, что это правда. Я никогда лично не был свидетелем ошибки синхронизации, когда я не обернул свой код в обработчик DOMContentLoaded. Конечно, вам понадобится обработчик load, если сначала нужно загрузить ресурсы, отличные от DOM. - person Jeffrey Sweeney; 03.01.2012
comment
Я тоже не согласен с этим. Если HTML-код, на который будет ссылаться сценарий, находится над сценарием, у меня никогда не было проблем. Если вам нужен доступ к изображениям из вашего скрипта, они могут быть не загружены - person Juan Mendes; 03.01.2012
comment
@JeffreySweeney Итак, вы думаете, что никогда не может быть никаких неожиданных последствий? А как насчет того, когда ОП обнаружит async или defer как способ ускорить процесс? Или они начинают добавлять разные файлы сценариев для подключаемых модулей jQuery, которые создают динамический HTML? Утверждение, что это всегда безопаснее... неверно? Когда небезопасно использовать .onload? - person ThinkingStiff; 03.01.2012
comment
@JuanMendes Я все еще утверждаю, что всегда безопаснее использовать его. См. мой комментарий к Джеффри. - person ThinkingStiff; 03.01.2012
comment
@ThinkingStiff Загрузка внешних скриптов = загрузка внешних ресурсов (извините меня, если я неправильно понял ваш последний пункт), но я соглашусь с вами по вашему предыдущему пункту. Я не имел в виду, что оборачивать код в DOMContentLoaded (или onload для внешних ресурсов) небезопасно, а только в том, что в этом нет необходимости. - person Jeffrey Sweeney; 03.01.2012
comment
@ThinkingStiff: мне бы хотелось увидеть пример, в котором скрипты внизу терпят неудачу; Я не понимаю, как два примера, которые вы упомянули, могут вызвать проблемы. Ваше утверждение всегда безопаснее слишком широкое и может снизить производительность (слишком долгое ожидание), поэтому я счел важным прокомментировать этот ответ. - person Juan Mendes; 04.01.2012
comment
@JuanMendes Я обновил ответ примером. ОП просто спросил, могут ли быть неожиданные последствия, и они могут быть. Я удалил рекомендацию DOMContentLoaded и дополнительно уточнил всегда использовать. - person ThinkingStiff; 04.01.2012
comment
@JeffreySweeney Я добавил пример, удалил DOMContentLoaded и дополнительно уточнил onload. - person ThinkingStiff; 04.01.2012
comment
@ThinkingStiff: в вашем примере используются изображения. В моем комментарии уже упоминалось, что если вам нужно, чтобы изображения загружались в ваш скрипт, вы должны использовать событие onload. Поэтому я по-прежнему считаю ненужным, если ваш скрипт не предполагает, что изображения предварительно загружены. - person Juan Mendes; 04.01.2012
comment
@JuanMendes Я добавил еще один пример, в котором не используются изображения. - person ThinkingStiff; 04.01.2012
comment
@ThinkingStiff: Спасибо за всю вашу работу здесь. Я всегда рад оказаться неправым. Однако я не понимаю, что должен тестировать ваш jsfiddle. Если ширина div не больше 100, то это ошибка? Почему? Это просто доказывает, что он был вызван после того, как анимация началась. В любом случае мой браузер (Chrome 16, Win 7) сбой для onLoad, nowrap и onDomReady. Я бы не хотел, чтобы весь ваш код работал медленнее, потому что вы не понимаете разницы между DOMReady (или скриптами внизу) и событием onload. - person Juan Mendes; 04.01.2012
comment
@JuanMendes fail просто означает, что onload и no wrap действуют по-разному. Поскольку результаты разные (по крайней мере, в браузере, который я тестировал), ваш код может ожидать один результат, а вместо этого выдает другой. С onload вы всегда получаете один и тот же ожидаемый результат: ширина, высота, расположение — все именно то, что вы установили в своих проектах. - person ThinkingStiff; 04.01.2012
comment
@ThinkingStiff: Но при загрузке вы должны дождаться загрузки всех ваших внешних файлов. Это цена, которую я не готов принять. Да, эти два события ведут себя по-разному, и вам нужно знать разницу. Если ваш скрипт зависит от изображений, вы должны дождаться загрузки, в противном случае нижняя часть тега body в порядке. - person Juan Mendes; 04.01.2012
comment
Если код ожидает, что изображение будет иметь определенную ширину, тогда код должен реализовать прослушиватель событий, чтобы обеспечить загрузку этого определенного изображения ... но не все изображения и css загружены. onLoad срабатывает поздно. Код не должен зависеть от document.onLoad. Браузеры строят дерево Dom сразу же после анализа документа, поэтому размещение скрипта непосредственно перед закрывающим тегом body должно выполнять свою работу. Ваш второй пример также не выглядит как реальный жизненный сценарий (я понимаю, но ... setTimeout?, если интервал был немного больше, onLoad тоже не помогает).‹br› Я вообще не понимаю вашу точку зрения. - person Boris D. Teoharov; 26.05.2013

Происходит несколько разных вещей.

  1. onload вызывается только после загрузки встроенного содержимого, например изображений. Это означает, что вы можете поместить код в onload, который зависит от наличия этого контента.
  2. готовые обработчики запускаются до этого, когда DOM (т.е. внутренняя структура) вашей страницы полностью загружена. Это не что отличается от помещения его внизу, но одно отличие состоит в том, что если кто-то уходит с вашей страницы, а затем возвращается, эти обработчики снова сработают.

Технически сценарии, запускаемые в конце документа, могут использовать такие методы, как getElementById, для извлечения уже обработанных элементов. Вы все еще можете поместить их в обработчик готовности или загрузки по вышеуказанным причинам. Это не означает, что сами скрипты не должны быть внизу — их присутствие все же дает преимущество для воспринимаемой производительности.

person Dan    schedule 03.01.2012
comment
Не могли бы вы написать несколько хороших статей, объясняющих, почему код внизу страницы нежелателен? Мне интересно узнать об этом больше. - person Jeffrey Sweeney; 03.01.2012
comment
Я не согласен с тем, что это не рекомендуется, developer.yahoo.com/performance/rules.html по-прежнему предлагает скрипты внизу - person Juan Mendes; 03.01.2012
comment
Извините, я не предлагал, чтобы скрипты не были внизу. Я пересмотрю это. - person Dan; 03.01.2012

Тег скрипта в нижней части HTML-страницы эквивалентен DOMContentLoaded. Весь html-код загружен, и теперь Javascript может обращаться к элементам DOM.

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

person Jeffrey Sweeney    schedule 03.01.2012