Тег сценарію - асинхронізація та відстрочка


547

У мене є кілька питань по приводу атрибутів asyncі deferдля <script>тега , який до мого розуміння роботи тільки в HTML5 браузерів.

Один з моїх сайтів має два зовнішніх файли JavaScript, які наразі сидять над </body>тегом; перший є Отримано з Google, а другий - локальний зовнішній сценарій.

З урахуванням швидкості завантаження сайту

  1. Чи є якась перевага в додаванні asyncдо двох сценаріїв, які я маю внизу сторінки?

  2. Чи буде якась перевага в додаванні цього asyncваріанту до двох сценаріїв і розміщенню їх у верхній частині сторінки в розділі <head>?

  3. Чи означає це, що вони завантажуються під час завантаження сторінки?
  4. Я припускаю, що це спричинить затримки для браузерів HTML4, але чи пришвидшить завантаження сторінки для браузерів HTML5?

Використання <script defer src=...

  1. Чи вплине навантаження двох сценаріїв всередині <head>атрибутом так deferсамо, як і раніше у скриптів </body>?
  2. Ще раз припускаю, що це уповільнить браузери HTML4.

Використання <script async src=...

Якщо у мене є два сценарії з asyncувімкненою

  1. Чи завантажували б їх одночасно?
  2. Або по черзі з рештою сторінки?
  3. Чи стає тоді порядок сценаріїв проблемою? Наприклад, один сценарій залежить від іншого, тому якщо один завантажується швидше, другий може не виконуватись правильно і т.д.

Нарешті, мені найкраще залишити речі такими, якими вони є, доки HTML5 більше не використовується?


5
asyncє новим (ish), але deferє частиною IE з IE4. deferбуло додано до інших браузерів набагато недавно, але старіші версії цих браузерів, як правило, зависають набагато менше.
Alohci

3
Тепер HTML5 став дуже популярним!
вересень08,

2
deferце те саме, що розміщення скриптів у нижній частині HTML, що є звичним протягом багатьох років.
vsync

1
@vsync не обов'язково відповідає дійсності, браузер завантажить JS з тегом відкладу, коли він аналізує тег сценарію, але відкладе виконання до прямого початку DOMContentLoaded. Завантаження не блокується. Розміщення в нижній частині HTML затримає завантаження та виконання JS до тих пір, поки DOM не буде побудований, але ви все одно матимете додаткову затримку, дочекавшись завантаження.
Бред Мороз

@BradFrost - Завантаження, на мій погляд, блокує, в тому сенсі, що вона займає пропускну здатність Інтернету, а для тих, хто має повільне з'єднання, я вважаю це обов'язково спочатку завантажити документ і лише потім, коли він буде наданий, почати завантажувати файли JavaScript. . Це справедливо у випадках, коли вміст не є щільно пов'язаним з javascript для візуалізації всього (наприклад, SPA )
vsync

Відповіді:


405

Зберігайте свої сценарії прямо раніше </body>. Асинхронізацію можна використовувати для скриптів, розташованих там за кількох обставин (див. Обговорення нижче). Відстрочка не призведе до великої різниці для скриптів, розташованих там, оскільки робота над розбором DOM у будь-якому випадку вже майже виконана.

Ось стаття, яка пояснює різницю між асинхронізацією та відкладанням: http://peter.sh/experiment/asynchronous-and-deferred-javascript-execution-explained/ .

Ваш HTML буде швидше відображатися в старих браузерах, якщо ви будете тримати сценарії в кінці тіла прямо раніше </body>. Отже, щоб зберегти швидкість завантаження у старих браузерах, ви не хочете розміщувати їх ніде більше.

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

Ви можете помістити сценарії в <head>тег і встановити їх, deferа завантаження скриптів буде відкладено доти, доки DOM не буде розібраний, і це отримає швидке відображення сторінки в нових браузерах, які підтримують відкладати, але це зовсім не допоможе вам. у старих браузерах, і це насправді не швидше, ніж просто встановити сценарії, перед </body>якими працює у всіх браузерах. Отже, ви можете зрозуміти, чому їх краще просто поставити прямо раніше </body>.

Async корисніше, коли вам дійсно все одно, коли скрипт завантажується, і нічого іншого, що залежить від користувача, залежить від завантаження цього сценарію. Найчастіше наводиться приклад використання async - це сценарій аналітики, такий як Google Analytics, який не хочеться нічого чекати, і його не потрібно терміново запускати, і він стоїть один, тому від цього нічого іншого не залежить.

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


8
Defer має запускати їх у порядку все-таки, але запускати до dom-contentloaded. Хіба це не означає, що введення його в голову було б швидше, оскільки він може почати завантажувати їх до того, як HTML-код тіла буде розібраний?
Кевін

9
Ви сказали, що введення сценаріїв headі встановлення їх deferне буде швидше, ніж їх розміщення раніше </body>, але з того, що я прочитав, це неправильно. Подумайте над цим - якщо ви вкладете сценарії <head>, вони почнуть завантажуватись негайно, тоді як якщо вони потрібні раніше, </body>то всі інші елементи спочатку завантажуються.
Нейт

12
@Nate - Це не змусить вашого документа завантажуватися швидше, що є моєю суттю. Ви впевнені, що це може швидше покращити завантаження сценарію, але це також може уповільнити завантаження документа та його вмісту, оскільки ви використовуєте частину своєї пропускної здатності та використовуєте одне з обмежених з'єднань, які браузер зробить до даного сервера для завантажте сценарій, хоча він також намагається завантажити ваш вміст.
jfriend00

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

2
На даний момент вимога </body> насправді не потрібна для розробок браузера з 2012 року, коли ця відповідь була розміщена.
bgcode

842

Це зображення пояснює звичайний тег сценарію, асинхронізацію та відстрочку

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

  • Сценарії асинхронізації виконуються, як тільки сценарій завантажується, тому він не гарантує порядок виконання (сценарій, який ви включили в кінці, може виконати до першого файлу сценарію)

  • Сценарії відстрочки гарантують порядок виконання, в якому вони відображаються на сторінці.

Перегляньте це посилання: http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html


Я думаю, що на прикладі з декількома сценаріями було б краще проілюструвати їх послідовність
vsync

4
@writofmandamus Схоже async, виграє. Дивіться stackoverflow.com/questions/13821151/…
монсеньйор

Дякую за гарне пояснення. Однак зображення не мають масштабу. У випадку лише <script>тегу загальна тривалість завантаження сторінки більша на час, необхідний для завантаження файлу сценарію.
arni

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

@arni Тільки якщо пропускна здатність повністю використана, що рідко є. І обидва завантаження поділяють пропускну здатність, а не блокують її. Далі: ці зображення показують зелений аналіз, а не завантажують.
Роберт Сімер

213

HTML5: async,defer

У HTML5 ви можете вказати веб-переглядачу, коли запустити JavaScript-код. Є 3 можливості:

<script       src="myscript.js"></script>

<script async src="myscript.js"></script>

<script defer src="myscript.js"></script>
  1. Без asyncабо deferбраузер запустить ваш сценарій негайно, перш ніж відобразити елементи, що знаходяться нижче вашого тегу сценарію.

  2. За допомогою async(асинхронного) браузер продовжить завантажувати HTML-сторінку та візуалізувати її, поки браузер завантажує та виконує скрипт одночасно.

  3. З defer, браузер запустить ваш сценарій, коли сторінка завершить розбір. (не потрібно закінчувати завантаження всіх файлів зображень. Це добре.)


Необхідний шаблон blogger.com, async=""перш ніж він перевірить і збереже зміни шаблону.
noobninja

1
Примітка. Немає гарантії, що сценарії запускатимуться в тому порядку, який вони вказали за допомогою Async. "Отже, якщо ваш другий сценарій залежить від першого сценарію, уникайте Async."
Faisal Naseer

2
async- Сценарії виконуються з моменту їх завантаження, не враховуючи їх порядок у файлі HTML.
vsync

30

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

Різниця між asyncі deferцентром навколо, коли виконується сценарій. Кожен asyncсценарій виконується при першій нагоді після його закінчення та перед початком події завантаження вікна. Це означає, що можливо (ймовірно), що asyncсценарії не виконуються в тому порядку, в якому вони виникають на сторінці. Тоді як deferсценарії, з іншого боку, гарантовано виконуються в тому порядку, в якому вони трапляються на сторінці. Це виконання починається після повного завершення розбору, але до DOMContentLoadedподії документа .

Джерело та додаткові деталі: тут .


24

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

Асинхронізація

Коли ви додасте атрибут async до тегу сценарію, станеться наступне.

<script src="myfile1.js" async></script>
<script src="myfile2.js" async></script>
  1. Зробіть паралельні запити для отримання файлів.
  2. Продовжуйте розбирати документ так, ніби він ніколи не був перерваний.
  3. Виконайте окремі сценарії в момент завантаження файлів.

Відкладіть

Defer дуже схожий на async з однією основною різницею. Ось що відбувається, коли браузер стикається зі сценарієм з атрибутом відкладання.

<script src="myfile1.js" defer></script>
<script src="myfile2.js" defer></script>
  1. Зробіть паралельні запити для отримання окремих файлів.
  2. Продовжуйте розбирати документ так, ніби він ніколи не був перерваний.
  3. Завершіть розбір документа, навіть якщо файли скриптів завантажили.
  4. Виконайте кожен сценарій у порядку, з яким вони стикалися в документі.

Довідка: Різниця між Async і Defer


7

asyncі deferзавантажить файл під час розбору HTML. Обидва не будуть перебивати парсер.

  • Сценарій з asyncатрибутом буде виконаний після його завантаження. Хоча сценарій з deferатрибутом буде виконуватися після завершення розбору DOM.

  • Завантажені сценарії asyncне гарантують жодного замовлення. У той час як сценарії, завантажені deferатрибутом, підтримують порядок їх появи в DOM.

Використовуйте, <script async>коли сценарій ні на що не покладається. коли сценарій залежить від використання.

Найкращим рішенням буде додавання внизу корпусу. З блокуванням чи візуалізацією не виникне проблем.


Просто хочу трохи уточнити тут, тут відбуваються дві речі 1. Завантаження ресурсу 2. Виконання ресурсу. Завантаження ресурсу в обох випадках (async та defer) не блокується, значить, вони не блокують розбір html, тоді як виконання в async блокує розбір, а в разі відстрочки виконання відбувається після розбору розмітки html, отже, не блокування в цьому випадку.
pOoO

5

Я думаю, що Джейк Арчібальд представив нам декілька розумінь ще в 2013 році, які можуть додати ще більшої позитивності темі:

https://www.html5rocks.com/en/tutorials/speed/script-loading/

У святого грааля є набір сценаріїв, які завантажуються негайно, не блокуючи візуалізацію, і виконуються якнайшвидше у тому порядку, коли вони були додані. На жаль, HTML ненавидить вас і не дозволить вам це зробити.

(...)

Відповідь насправді є специфікацією HTML5, хоча вона прихована внизу розділу завантаження сценаріїв. " Атрибут IDL асинхронізації контролює, чи буде елемент виконувати асинхронно чи ні. Якщо встановлено прапор" сила-асинхронізація "елемента, то після отримання атрибут IDL асинхроніки повинен повернути істинне, а при встановленні -" сила-асинхронізація " прапор спочатку потрібно зняти… ".

(...)

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

[
    '//other-domain.com/1.js',
    '2.js'
].forEach(function(src) {
    var script = document.createElement('script');
    script.src = src;
    script.async = false;
    document.head.appendChild(script);
});

Це дає нашим сценаріям поєднання поведінки, яке неможливо досягти за допомогою простого HTML. Очевидно, що не асинхронізуються, сценарії додаються до черги виконання, та сама черга, яку вони додаються у нашому першому простому прикладі HTML. Однак, будучи динамічно створеними, вони виконуються за межами розбору документів, тому візуалізація не блокується під час їх завантаження (не плутайте завантаження сценарію not-async з синхронізацією XHR, що ніколи не є корисною справою).

Сценарій, зазначений вище, повинен бути включений в рядку на заголовку сторінок, якнайшвидше завантажуючи чергу скриптів, не порушуючи прогресивне відображення, і виконувати якнайшвидше у визначеному вами порядку. "2.js" безкоштовно завантажувати перед "1.js", але він не буде виконуватися, поки "1.js" не буде успішно завантажено і виконано, або не вдасться зробити це. Ура! завантаження async, але замовлене виконання !

Але все-таки це не найшвидший спосіб завантаження скриптів:

(...) На наведеному вище прикладі браузер повинен проаналізувати та виконати сценарій, щоб виявити, які сценарії завантажити. Це приховує ваші сценарії від сканерів попереднього завантаження. Браузери використовують ці сканери для пошуку ресурсів на сторінках, які ви, ймовірно, відвідаєте наступні, або виявлення ресурсів сторінки, поки аналізатор заблокований іншим ресурсом.

Ми можемо додати можливість відкриття, помістивши це в голову документа:

<link rel="subresource" href="//other-domain.com/1.js">
<link rel="subresource" href="2.js">

Це говорить про те, що веб-переглядачу потрібні сторінки 1.js та 2.js. link [rel = subresource] схожий на посилання [rel = prefetch], але з різною семантикою. На жаль, на даний момент він підтримується лише в Chrome, і ви повинні оголосити, які сценарії завантажувати двічі, один раз за допомогою елементів посилання та знову у вашому сценарії.

Виправлення: я спочатку заявив, що їх забрав сканер попереднього завантаження, їх немає, їх підбирає звичайний аналізатор. Однак сканер попереднього завантаження міг би їх забрати, він просто ще не існує, тоді як сценарії, включені до виконуваного коду, ніколи не можуть бути попередньо завантажені. Дякую Йоаву Вайсу, який виправив мене в коментарях.


1

Здається, поведінка відстрочки та асинхронізації залежить від браузера, принаймні, на етапі виконання. ПРИМІТКА, відстрочка застосовується лише до зовнішніх скриптів. Я припускаю, що асинхронізація йде за тією ж схемою.

У IE 11 і нижче порядок здається таким:

  • async (може частково виконуватись під час завантаження сторінки)
  • жоден (не може виконуватись під час завантаження сторінки)
  • відкладати (виконується після завантаження сторінки, все відкладається в порядку розміщення у файлі)

В Edge, Webkit тощо атрибут async, здається, або ігнорується, або розміщується в кінці:

  • data-pagespeed-no-defer (виконується перед будь-якими іншими сценаріями, поки сторінка завантажується)
  • жоден (не може виконатись під час завантаження сторінки)
  • відкладати (чекає, поки завантажиться DOM, все відкладається в порядку розміщення у файлі)
  • async (схоже, чекає завантаження DOM)

У нових браузерах атрибут data-pagespeed-no-defer працює перед будь-якими іншими зовнішніми сценаріями. Це для сценаріїв, які не залежать від DOM.

ПРИМІТКА. Використовуйте відстрочку, коли вам потрібно чіткий порядок виконання зовнішніх скриптів. Це повідомляє браузеру виконувати всі відкладені сценарії в порядку розміщення у файлі.

ВІДПОВІДЬ: Розмір зовнішніх javascripts мав значення при завантаженні ..., але не впливав на порядок виконання.

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


data-pagespeed-no-deferце атрибут, який використовується серверним модулем PageSpeed ​​на стороні сервера . Сам data-pagespeed-no-deferатрибут не впливає на жоден браузер.
Qtax
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.