Tag skryptu - asynchronizacja i odraczanie


547

Mam kilka pytań o atrybutach asynci deferdla <script>tagu, który w moim rozumieniu tylko pracy w HTML5 przeglądarek.

Jedna z moich witryn ma dwa zewnętrzne pliki JavaScript, które obecnie znajdują się tuż nad </body>tagiem; pierwszy to pochodzi z Google, a drugi to lokalny skrypt zewnętrzny.

W odniesieniu do prędkości ładowania strony

  1. Czy jest jakaś korzyść z dodania asyncdo dwóch skryptów, które mam na dole strony?

  2. Czy byłoby jakąś zaletą dodanie asyncopcji do dwóch skryptów i umieszczenie ich na górze strony w <head>?

  3. Czy to znaczy, że pobierają się podczas ładowania strony?
  4. Zakładam, że spowodowałoby to opóźnienia w przeglądarkach HTML4, ale czy przyspieszyłoby to ładowanie strony w przeglądarkach HTML5?

Za pomocą <script defer src=...

  1. Czy załadowanie dwóch skryptów wewnątrz <head>z atrybutem miałoby defertaki sam wpływ, jak posiadanie skryptów wcześniej </body>?
  2. Po raz kolejny zakładam, że spowolniłoby to przeglądarkę HTML4.

Za pomocą <script async src=...

Jeśli mam dwa skrypty z asyncwłączoną funkcją

  1. Czy będą pobierać w tym samym czasie?
  2. A może pojedynczo z resztą strony?
  3. Czy kolejność skryptów staje się wtedy problemem? Na przykład jeden skrypt zależy od drugiego, więc jeśli jeden pobierze szybciej, drugi może nie działać poprawnie itp.

Wreszcie, czy najlepiej zostawić rzeczy takimi, jakie są, dopóki HTML5 nie będzie częściej używany?


5
asyncjest nowy (ish), ale deferjest częścią IE od IE4. deferzostał dodany do innych przeglądarek znacznie niedawno, ale starsze wersje tych przeglądarek mają tendencję do zawieszania się o wiele mniej.
Alohci

3
Teraz HTML5 stał się bardzo popularny!
08

2
deferto tak samo, jak umieszczanie skryptów na dole HTML, co jest powszechne od wielu lat.
vsync

1
@vsync niekoniecznie jest prawdą, przeglądarka pobierze JS ze znacznikiem odroczenia, gdy przeanalizuje znacznik skryptu, ale odłoży egzekucję na chwilę przed DOMContentLoaded. Pobieranie nie blokuje. Umieszczenie na dole kodu HTML opóźni pobieranie i wykonanie JS do momentu zbudowania DOM, ale nadal będziesz ponosił dodatkowe opóźnienie, czekając na pobranie.
Brad Frost

@BradFrost - Moim zdaniem pobieranie blokuje, w tym sensie, że zajmuje przepustowość Internetu, a dla tych, którzy mają wolne połączenie, uważam za konieczne, aby najpierw załadować dokument, a dopiero po jego renderowaniu zacznij pobierać pliki javascript . Dzieje się tak w przypadkach, gdy treść nie jest ściśle powiązana z javascript do renderowania wszystkiego (jak SPA )
vsync

Odpowiedzi:


405

Zachowaj skrypty wcześniej </body>. Asynchronii można używać ze skryptami znajdującymi się tam w kilku okolicznościach (patrz dyskusja poniżej). Odroczenie nie zrobi dużej różnicy dla skryptów znajdujących się tam, ponieważ i tak parsowanie DOM zostało już wykonane.

Oto artykuł wyjaśniający różnicę między asynchronizacją a odroczeniem: http://peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/ .

Twój HTML będzie wyświetlać się szybciej w starszych przeglądarkach, jeśli skrypty znajdują się na końcu treści tuż przed </body>. Aby zachować szybkość ładowania w starszych przeglądarkach, nie chcesz umieszczać ich nigdzie indziej.

Jeśli drugi skrypt zależy od pierwszego skryptu (np. Drugi skrypt korzysta z jQuery załadowanego w pierwszym skrypcie), nie można ich asynchronizować bez dodatkowego kodu sterującego kolejnością wykonywania, ale można je odroczyć, ponieważ skrypty odroczone nadal będą wykonywane w kolejności, ale dopiero po przeanalizowaniu dokumentu. Jeśli masz ten kod i nie potrzebujesz skryptów do natychmiastowego uruchomienia, możesz ustawić je jako asynchroniczne lub odraczać.

Możesz umieścić skrypty w <head>tagu i ustawić je, defera ładowanie skryptów zostanie odroczone do momentu parsowania DOM, co zapewni szybkie wyświetlanie strony w nowych przeglądarkach, które obsługują odraczanie, ale to wcale ci nie pomoże w starszych przeglądarkach i nie jest tak naprawdę szybsze niż po prostu umieszczenie skryptów tuż przed tym, </body>co działa we wszystkich przeglądarkach. Możesz więc zrozumieć, dlaczego najlepiej jest umieścić je wcześniej </body>.

Asynchronizacja jest bardziej przydatna, gdy naprawdę nie obchodzi Cię, kiedy skrypt się ładuje i nic innego, co jest zależne od użytkownika, nie zależy od ładowania skryptu. Najczęściej cytowanym przykładem użycia asynchronizacji jest skrypt analityczny, taki jak Google Analytics, na który nie chcesz czekać i nie trzeba go szybko uruchamiać, a działa on samodzielnie, więc nic innego od tego nie zależy.

Zwykle biblioteka jQuery nie jest dobrym kandydatem do asynchronizacji, ponieważ zależą od niej inne skrypty i chcesz zainstalować procedury obsługi zdarzeń, aby strona mogła zacząć reagować na zdarzenia użytkownika i może być konieczne uruchomienie kodu inicjującego opartego na jQuery w celu ustalenia stanu początkowego strony. Można go użyć asynchronicznie, ale inne skrypty będą musiały zostać zakodowane, aby nie zostały uruchomione do momentu załadowania jQuery.


8
Odroczenie powinno uruchamiać je w kolejności, ale uruchamiać przed załadowaniem zawartości dom. Czy to nie znaczy, że włożenie go do głowy byłoby szybsze, ponieważ może zacząć je pobierać PRZED analizowaniem kodu HTML?
Kevin

9
Powiedziałeś, że wstawianie skryptów headi ustawianie ich defernie będzie szybsze niż wstawianie ich wcześniej </body>, ale z tego, co przeczytałem, jest to nieprawidłowe. Pomyśl o tym - jeśli włożysz skrypty <head>, zaczną one natychmiast pobierać, a jeśli są w porządku, </body>wszystkie pozostałe elementy zostaną pobrane jako pierwsze.
Nate

12
@Nate - Nie przyspieszy ładowania twojego dokumentu, o co mi chodzi. Masz rację, że może to przyspieszyć ładowanie skryptu wcześniej, ale może również spowolnić ładowanie dokumentu i jego zawartości, ponieważ używasz części przepustowości i jednego z ograniczonych połączeń, które przeglądarka nawiąże z danym serwerem w celu wczytaj skrypt, gdy próbuje on załadować zawartość.
jfriend00

4
„Jeśli twój drugi skrypt zależy od pierwszego skryptu ... to nie możesz ich zmusić do asynchronizacji lub odroczenia” - to nieprawda, z odroczeniem wykonania w kolejności.
DisgruntledGoat

2
W tym momencie wymaganie </body> nie jest tak naprawdę konieczne w przypadku przeglądarek od 2012 r., Kiedy opublikowano tę odpowiedź.
bgcode

842

Ten obraz wyjaśnia normalny tag skryptu, asynchronizację i odroczenie

wprowadź opis zdjęcia tutaj

  • Skrypty asynchroniczne są wykonywane natychmiast po załadowaniu skryptu, więc nie gwarantuje kolejności wykonywania (skrypt podany na końcu może zostać wykonany przed pierwszym plikiem skryptu)

  • Odroczone skrypty gwarantują kolejność wykonywania, w jakiej pojawiają się na stronie.

Zobacz ten link: http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html


Myślę, że przykład z wieloma skryptami lepiej zilustrować ich sekwencję
vsync

4
@writofmandamus Wygląda na to, asyncże wygra. Zobacz stackoverflow.com/questions/13821151/…
Monsignor,

Dzięki za dobre wyjaśnienie. Jednak obrazy nie są skalowane. W przypadku samego <script>znacznika całkowita długość ładowania strony jest większa o czas potrzebny do pobrania pliku skryptu.
arni

@BhavikHirani Według tej strony używanie zarówno asynchronizacji, jak i odroczenia w tym samym tagu skryptu używa asynchronizacji, jeśli przeglądarka go obsługuje, lub wraca do odroczenia, jeśli nie obsługuje asynchronizacji, ale obsługuje odraczanie. Zachowania są bardzo różne, więc nie radzę używać obu, ponieważ wynik jest nieprzewidywalny i może być doskonałym źródłem błędów.
Adrian Wiik

@arni Tylko wtedy, gdy przepustowość jest w pełni wykorzystywana, co rzadko. Oba pliki do pobrania dzielą szerokość pasma, a nie blokują jeden. - Ponadto: te obrazy pokazują parsowanie na zielono, a nie pobieranie.
Robert Siemer

213

HTML5: async,defer

W HTML5 możesz powiedzieć przeglądarce, kiedy uruchomić kod JavaScript. Istnieją 3 możliwości:

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

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

<script defer src="myscript.js"></script>
  1. Bez asynclub deferprzeglądarka natychmiast uruchomi skrypt, zanim wyrenderuje elementy znajdujące się poniżej tagu skryptu.

  2. W przypadku async(asynchronicznego) przeglądarka będzie nadal ładować stronę HTML i renderować ją, jednocześnie ładując i wykonując skrypt.

  3. Dzięki deferprzeglądarce przeglądarka uruchomi skrypt, gdy strona zakończy przetwarzanie. (nie trzeba kończyć pobierania wszystkich plików obrazów. To dobrze.)


Szablon blogger.com jest wymagany async=""przed sprawdzeniem poprawności i zapisaniem zmian w szablonie.
noobninja

1
Uwaga: nie ma gwarancji, że skrypty będą działały w kolejności, w jakiej zostały określone za pomocą Async. „Więc jeśli twój drugi skrypt zależy od pierwszego skryptu, unikaj Async.”
Faisal Naseer

2
async- Skrypty są wykonywane od momentu ich pobrania, bez względu na ich kolejność w pliku HTML.
vsync

30

Oba asynci deferskrypty zaczynają się natychmiast pobierać bez wstrzymywania analizatora składni i oba obsługują opcjonalny onloadmoduł obsługi, aby zaspokoić powszechną potrzebę inicjalizacji, która zależy od skryptu.

Różnica między asynci deferkoncentruje się wokół wykonywania skryptu. Każdy asyncskrypt jest uruchamiany przy pierwszej okazji po zakończeniu pobierania i przed zdarzeniem ładowania okna. Oznacza to, że możliwe (i prawdopodobne), że asyncskrypty nie są wykonywane w kolejności, w jakiej występują na stronie. Podczas gdy deferskrypty z drugiej strony są gwarantowane w kolejności, w jakiej występują na stronie. Wykonanie rozpoczyna się po całkowitym zakończeniu analizy, ale przed DOMContentLoadedzdarzeniem dokumentu .

Źródło i dalsze szczegóły: tutaj .


24

W obliczu tego samego rodzaju problemu i teraz zrozumiałe, jak oba będą działać. Mam nadzieję, że ten link referencyjny będzie pomocny ...

Asynchronizacja

Po dodaniu atrybutu async do tagu skryptu wystąpią następujące zdarzenia.

<script src="myfile1.js" async></script>
<script src="myfile2.js" async></script>
  1. Złóż równoległe żądania pobrania plików.
  2. Kontynuuj parsowanie dokumentu, tak jakby nigdy nie został przerwany.
  3. Wykonaj poszczególne skrypty w momencie pobierania plików.

Odraczać

Odroczenie jest bardzo podobne do asynchronicznego z jedną zasadniczą różnicą. Oto, co się dzieje, gdy przeglądarka napotka skrypt z atrybutem odroczenia.

<script src="myfile1.js" defer></script>
<script src="myfile2.js" defer></script>
  1. Składaj równoległe wnioski o pobranie poszczególnych plików.
  2. Kontynuuj parsowanie dokumentu, tak jakby nigdy nie został przerwany.
  3. Zakończ parsowanie dokumentu, nawet jeśli pliki skryptów zostały pobrane.
  4. Wykonaj każdy skrypt w kolejności, w jakiej napotkano w dokumencie.

Odniesienie: Różnica między Asyncem a odroczeniem


7

asynci deferpobierze plik podczas analizy HTML. Oba nie przerywają analizatora składni.

  • Skrypt z asyncatrybutem zostanie wykonany po pobraniu. Podczas gdy skrypt z deferatrybutem zostanie wykonany po zakończeniu analizy DOM.

  • Załadowane skrypty asyncnie gwarantują żadnego zamówienia. Podczas gdy skrypty ładowane z deferatrybutem zachowują kolejność, w jakiej pojawiają się w DOM.

Użyj, <script async>gdy skrypt nie polega na niczym. kiedy skrypt zależy od użycia.

Najlepszym rozwiązaniem byłoby dodanie dolnej części ciała. Nie będzie problemu z blokowaniem lub renderowaniem.


Po prostu chcę tutaj wyjaśnić, dzieją się tutaj dwie rzeczy: 1. Pobieranie zasobu 2. Wykonanie zasobu. Pobieranie zasobów w obu przypadkach (asynchroniczne i odraczanie) nie blokuje, oznacza to, że nie blokuje parsowania HTML, podczas gdy wykonywanie w asynchronii blokuje parsowanie, aw przypadku odroczenia wykonywanie następuje po przeanalizowaniu znaczników HTML, stąd w tym przypadku nie blokuje.
pOoOf z

5

Myślę, że Jake Archibald przedstawił nam pewne spostrzeżenia w 2013 roku, które mogą dodać jeszcze więcej pozytywności do tematu:

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

Święty Graal natychmiast pobiera zestaw skryptów, nie blokując renderowania, i wykonuje je jak najszybciej w kolejności, w jakiej zostały dodane. Niestety HTML cię nienawidzi i nie pozwala ci tego zrobić.

(...)

Odpowiedź znajduje się w specyfikacji HTML5, chociaż jest ukryta u dołu sekcji ładowania skryptów. „ Atrybut async IDL kontroluje, czy element będzie wykonywany asynchronicznie, czy nie. Jeśli ustawiona jest flaga„ force-async ”, to po uzyskaniu atrybutu async IDL musi zwrócić wartość true, a po ustawieniu„ force-async ” flaga musi być najpierw rozbrojona… ”.

(...)

Skrypty tworzone dynamicznie i dodawane do dokumentu są domyślnie asynchroniczne , nie blokują renderowania i nie są uruchamiane natychmiast po pobraniu, co oznacza, że ​​mogą wyjść w niewłaściwej kolejności. Możemy jednak wyraźnie oznaczyć je jako niesynchroniczne:

[
    '//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);
});

To daje naszym skryptom mieszankę zachowań, których nie da się osiągnąć za pomocą zwykłego HTML. Ponieważ jawnie nie są asynchroniczne, skrypty są dodawane do kolejki wykonawczej, tej samej kolejki, do której zostały dodane w naszym pierwszym przykładzie w formacie HTML. Ponieważ są tworzone dynamicznie, są wykonywane poza analizą dokumentów, więc renderowanie nie jest blokowane podczas pobierania (nie należy mylić ładowania niesynchronizowanego skryptu z synchronizacją XHR, co nigdy nie jest dobre).

Powyższy skrypt powinien zostać uwzględniony w nagłówku stron, kolejkując pobieranie skryptów tak szybko, jak to możliwe, bez zakłócania renderowania progresywnego, i wykonuje się tak szybko, jak to możliwe, w podanej kolejności. „2.js” można pobrać za darmo przed „1.js”, ale nie zostanie wykonane, dopóki „1.js” nie zostanie pomyślnie pobrane i wykonane lub nie wykona żadnego z nich. Hurra! pobieranie asynchroniczne, ale wykonanie zlecone !

Mimo to może to nie być najszybszy sposób ładowania skryptów:

(...) W powyższym przykładzie przeglądarka musi przeanalizować i wykonać skrypt, aby dowiedzieć się, które skrypty należy pobrać. To ukrywa twoje skrypty przed skanerami wstępnego ładowania. Przeglądarki używają tych skanerów do odkrywania zasobów na stronach, które prawdopodobnie będziesz odwiedzać dalej, lub odkrywania zasobów strony, gdy analizator jest zablokowany przez inny zasób.

Możemy ponownie dodać wykrywalność, umieszczając to w nagłówku dokumentu:

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

Mówi to przeglądarce, że strona potrzebuje wersji 1.js i 2.js. link [rel = subresource] jest podobny do link [rel = prefetch], ale ma inną semantykę. Niestety, obecnie jest obsługiwany tylko w Chrome i musisz zadeklarować, które skrypty załadować dwukrotnie, raz za pomocą elementów linku i ponownie w skrypcie.

Korekta: pierwotnie stwierdziłem, że zostały one pobrane przez skaner wstępnego ładowania, nie są, są one odbierane przez zwykły parser. Jednak skaner wstępnego ładowania może je pobrać, po prostu jeszcze tego nie robi, podczas gdy skrypty zawarte w kodzie wykonywalnym nigdy nie mogą zostać wstępnie załadowane. Dzięki Yoav Weiss, który poprawił mnie w komentarzach.


1

Wygląda na to, że zachowanie odroczenia i asynchronizacji zależy od przeglądarki, przynajmniej od fazy wykonania. UWAGA, odroczenie dotyczy tylko zewnętrznych skryptów. Zakładam, że asynchronizacja przebiega według tego samego wzorca.

W IE 11 i niższych kolejność wygląda następująco:

  • asynchroniczny (może częściowo zostać uruchomiony podczas ładowania strony)
  • none (można wykonać podczas ładowania strony)
  • odrocz (wykonuje po załadowaniu strony, wszystkie odkłada w kolejności umieszczenia w pliku)

W Edge, Webkit itp. Atrybut asynchroniczny wydaje się być ignorowany lub umieszczony na końcu:

  • data-pagespeed-no-defer (wykonuje się przed innymi skryptami podczas ładowania strony)
  • none (można wykonać podczas ładowania strony)
  • odłóż (czeka na załadowanie DOM, wszystkie odłóż w kolejności umieszczenia w pliku)
  • asynchroniczny (wydaje się czekać na załadowanie DOM)

W nowszych przeglądarkach atrybut data-pagespeed-no-defer działa przed innymi zewnętrznymi skryptami. Dotyczy to skryptów, które nie zależą od DOM.

UWAGA: Użyj odroczenia, gdy potrzebujesz jawnej kolejności wykonywania zewnętrznych skryptów. Mówi to przeglądarce, aby wykonała wszystkie odroczone skrypty w kolejności umieszczenia w pliku.

NA BOK: Rozmiar zewnętrznych javascripts miał znaczenie podczas ładowania ... ale nie miał wpływu na kolejność wykonywania.

Jeśli martwisz się wydajnością swoich skryptów, możesz rozważyć miniaturyzację lub po prostu dynamicznie ładować je za pomocą XMLHttpRequest.


data-pagespeed-no-deferjest atrybutem używanym przez moduł PageSpeed ​​po stronie serwera . Sam atrybut nie działa w żadnej przeglądarce. data-pagespeed-no-defer
Qtax,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.