Як саме працює <script defer = "defer">?


208

У мене є кілька <script>елементів, і код в деяких з них залежить від коду в інших <script>елементах. Я бачив, що deferатрибут може стати в нагоді тут, оскільки він дозволяє відкласти кодові блоки у виконанні.

Щоб перевірити це, я виконав це в Chrome: http://jsfiddle.net/xXZMN/ .

<script defer="defer">alert(2);</script>
<script>alert(1)</script>
<script defer="defer">alert(3);</script>

Однак він попереджає 2 - 1 - 3. Чому це не насторожує 1 - 2 - 3?


2
Можливо, ознайомтеся з цією статтею . І, як завжди, IE має власну думку про те, що щось означає, і вирішив спочатку завантажити сценарій, але затримати виконання, поки тіло не завантажується (як правило).
Бред Крісті

Дякуємо, проте тестова сторінка має інший результат у Chrome: websiteoptimization.com/speed/tweak/defer/test . На екрані екрана показано, як я цього очікував, тоді як Chrome, здається, спочатку виконав відкладений.
pimvdb

1
Я думаю, ви знайдете визначення IE відкладення, яке відповідає наміру W3C відкласти в специфікації DOM рівня 1.
Позначити у Ramp51

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

2
@Pankrat Справжня історія! Спробуйте jsfiddle.net/xXZMN/50 Тестовано у Firefox24
m93a

Відповіді:


51

ОНОВЛЕНО: 19.02.2016

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


В основному, відкладати повідомляє браузеру почекати "до готовності", перш ніж виконати javascript у цьому блоці сценаріїв. Зазвичай це відбувається після того, як DOM закінчив завантаження і document.readyState == 4

Атрибут відстрочки специфічний для Internet Explorer. В Internet Explorer 8 в Windows 7 результат, який я бачу на вашій тестовій сторінці JS Fiddle, - 1 - 2 - 3.

Результати можуть відрізнятися від браузера до браузера.

http://msdn.microsoft.com/en-us/library/ms533719(v=vs.85).aspx

Всупереч загальноприйнятій думці, IE дотримується стандартів частіше, ніж люди пускають, фактично атрибут "відкладати" визначається у специфікації DOM рівня 1 http://www.w3.org/TR/REC-DOM-Level-1/level -one-html.html

Визначення відстрочки W3C: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer :

"Якщо встановлено, цей булевий атрибут надає натяку користувачеві агент, що скрипт не збирається генерувати будь-який вміст документа (наприклад, відсутність" document.write "в JavaScript), і таким чином, користувальницький агент може продовжувати розбір та візуалізацію."


8
@ MarkAtRamp51 - Якщо ваша відповідь застаріла, слід відредагувати її, а не скаржитися на зворотні коментарі в коментарях до інших відповідей. Загальні відомості призначені для відповідей, які "не корисні".
Крістіан Конкл

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

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

3
@Leo, чи не слід це позначити тоді? Шукаючи "html5 сценарій відстрочки", це третій результат у google. Тоді ця відповідь надає багатьом користувачам застаріле і неправильне визначення. (Поточне визначення: "Вказує, що агент користувача може відкладати обробку сценарію. Див. Визначення атрибута відстрочки в HTML 4.0.").
Малавос

2
@ MarkAtRamp51Я думаю, вам слід оновити свою відповідь. Кожен, хто знайде це питання, і тому ваша відповідь, не визнає його історичну інформацію. На них це буде виглядати так, як це відповідь, яка є правильною сьогодні. Ось так працює Інтернет. Тож слід відредагувати свою відповідь, зауваживши, що вона була правильною колись, і посилатися на правильну відповідь.
Juuro

167

Кілька фрагментів із специфікації HTML5: http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

Атрибути відстрочки та асинхронізації не повинні бути вказані, якщо атрибут src відсутній.


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


Точні деталі обробки цих атрибутів, з більшості історичних причин, є дещо нетривіальними, включаючи ряд аспектів HTML. Таким чином, вимоги до впровадження по необхідності розкидані по всій специфікації. Алгоритми, наведені нижче (у цьому розділі), описують серцевину цієї обробки, але ці алгоритми посилаються та посилаються на правила розбору для початкових і кінцевих тегів сценарію в HTML, в іноземному вмісті та XML, правилах документа.write () метод, поводження з сценарієм тощо.


Якщо в елементі є атрибут src, а в елементі є атрибут defer, а елемент позначений як "вставлений парсер", а в елемента немає атрибута асинхронізації:

Елемент повинен бути доданий до кінця списку сценаріїв, який буде виконуватися після завершення розбору документа, пов'язаного з документом аналізатора, який створив елемент.


37
Можливо, моя відповідь тут не дозволить людям відмовитися від голосування за мою відповідь через ваш не корисний коментар. Прийнята відповідь не є помилковою, відповідь відрізняється, оскільки на початку 2011 року специфікація HTML5 була менш актуальною для основних веб-браузерів, ніж зараз. Ця відповідь, можливо, буде краще рухатися вперед, але прийнята відповідь НЕ ВИМОГА за будь-яким стандартом.
Позначте у Ramp51

3
Хоча корисно знати, що говорить специфікація, виявляється, що деякі браузери, як IE <9, deferпогано реалізуються . Якщо ви використовуєте defer, ви не можете розраховувати на те, що файли скриптів виконуються в порядку в деяких браузерах.
Flimm


Перша цитата вже не дійсна, правда? Тепер я можу прочитати це: "Атрибут не повинен бути вказаний, якщо атрибут src відсутній, або якщо сценарій не є класичним сценарієм." І класичний сценарій - це теж без src = "".
Фелікс Санц

158

Справжня відповідь така: Тому що ви не можете довіряти відкладенню.

Поняття відкладення та асинхронізація відрізняються наступним чином:

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

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

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

  • У певних ситуаціях у деяких браузерах є помилка, яка спричиняє deferневдачу сценаріїв.
  • Деякі браузери затримують DOMContentLoadedподію до моменту завантаження deferсценаріїв, а деякі не.
  • Деякі браузери підкоряються deferна <script>елементах з інлайн кодом і без srcатрибута, і деякі його ігнорувати.

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

<script defer async src="..."></script>

98% браузерів, які використовуються у всьому світі та 99% у США, уникатимуть блокування при такому підході.

(Якщо вам потрібно зачекати, поки документ закінчить розбір, прослухайте подію DOMContentLoadedподії або скористайтеся зручною .ready()функцією jQuery . Ви все одно хочете зробити це, щоб витончено повернутися до браузерів, які взагалі не реалізують defer.)


13
Дякую, ваша відповідь була для мене найбільш корисною!
Маркус

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

1
@tinkerr У концепції ви праві; на практиці це не виявляється правдою. Оскільки воно не реалізується послідовно, гарантія послідовності не є універсальною, а значить, не є гарантією. Реалізуючи щось, ви дбаєте про виконання. Намір дизайну милий, але не особливо корисний.
Кріс Москіні

Просто хотілося зазначити, що Opera підтримує deferатрибут з версії 15 , яка вийшла 2 червня 2013 року .

1
@VikasBansal Для старих веб-переглядачів, які не підтримують асинхронізацію, а саме старшого IE.
Кріс Москіні

13

deferможе використовуватися в <script>тегу лише для включення зовнішнього сценарію . Тому рекомендується використовувати в <script>-tags в <head>-сече-.


8

Оскільки атрибут defer працює лише з тегом скриптів з src. Знайшов спосіб імітувати відстрочку для вбудованих сценаріїв. Використовуйте подію DOMContentLoaded.

<script defer src="external-script.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
    // Your inline scripts which uses methods from external-scripts.
});
</script>

Це тому, що DOMContentLoaded події спрацьовує після відкладених сценаріїв, віднесених повністю, повністю завантажені.


6

Атрибут defer призначений лише для зовнішніх сценаріїв (слід використовувати лише за наявності атрибуту src).



4

Подивіться на цю чудову статтю Глибоке занурення у мутні води завантаження скриптів розробником Google Джейком Арчібальдом, написане у 2013 році

Цитуючи відповідний розділ цієї статті:

Відкладіть

<script src="//other-domain.com/1.js" defer></script>
<script src="2.js" defer></script>

Spec каже : Завантажте разом, виконайте замовлення безпосередньо перед DOMContentLoaded. Ігноруйте "відкладати" сценарії без "src".

IE <10 говорить : я можу виконати 2.js на півдорозі виконання 1.js. Хіба це не весело ??

Червоні браузери кажуть : я поняття не маю, що це за «відстрочка», я буду завантажувати сценарії так, ніби його там не було.

Інші браузери кажуть : Гаразд, але я не можу ігнорувати "відкладати" сценарії без "src".

(Додаю, що ранні версії Firefox запускають DOMContentLoaded до того, як deferсценарії закінчаться, відповідно до цього коментаря .)

Сучасні браузери здаються, що вони asyncналежним чином підтримують , але вам потрібно бути в порядку, коли сценарії закінчуються, можливо, перед DOMContentLoaded.


1

Цей атрибут Boolean встановлений, щоб вказувати браузеру, що сценарій повинен бути виконаний після розбору документа. Оскільки ця функція ще не реалізована у всіх інших основних браузерах, автори не повинні вважати, що виконання сценарію насправді буде відкладено. Ніколи не дзвоніть document.write () зі сценарію відкладання (оскільки Gecko 1.9.2, це вимкне документ). Атрибут defer не повинен використовуватися для скриптів, у яких немає атрибута src. Оскільки Gecko 1.9.2, атрибут defer ігнорується у скриптах, у яких немає атрибуту src. Однак у Gecko 1.9.1 навіть вбудовані сценарії відкладаються, якщо встановлено атрибут defer.

defer працює з хромом, firefox, тобто> 7 та Safari

посилання: https://developer.mozilla.org/en-US/docs/HTML/Element/script


0

Атрибут defer - булевий атрибут.

При наявності він визначає, що сценарій виконується після того, як сторінка закінчила розбір.

Примітка: Атрибут defer призначений лише для зовнішніх сценаріїв (слід використовувати лише за наявності атрибуту src).

Примітка. Існує кілька способів виконання зовнішнього скрипту:

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

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