Jak dokładnie działa <script defer = „defer”>?

208

Mam kilka <script>elementów, a kod w niektórych z nich zależy od kodu w innych <script>elementach. Widziałem, że ten deferatrybut może się tu przydać, ponieważ umożliwia odłożenie bloków kodu w trakcie wykonywania.

Aby to przetestować, wykonałem to w Chrome: http://jsfiddle.net/xXZMN/ .

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

Ostrzega jednak 2 - 1 - 3. Dlaczego nie alarmuje 1 - 2 - 3?

pimvdb
źródło
2
Może sprawdź ten artykuł . I, jak zawsze, IE ma własne zdanie na temat tego, co coś znaczy, i postanowił najpierw załadować skrypt, ale opóźnić wykonanie do momentu załadowania treści (zwykle).
Brad Christie,
Dzięki, jednak strona testowa ma inny wynik w Chrome: websiteoptimization.com/speed/tweak/defer/test . Zrzut ekranu pokazuje, jak bym się tego spodziewał, podczas gdy Chrome wydaje się najpierw wykonywać odroczony.
pimvdb
1
Myślę, że znajdziesz definicję odroczenia w IE, zgodną z intencją W3C dotyczącą odroczenia w specyfikacji DOM Level 1.
Mark At Ramp51
41
Jak już wskazał Alohci w swojej odpowiedzi, zgodnie ze standardem HTML defer obowiązuje tylko przy określaniu src. Może to być powód, dla którego twój przykład nie działał zgodnie z oczekiwaniami w większości przeglądarek.
Pankrat
2
@Pankrat Prawdziwa historia! Wypróbuj jsfiddle.net/xXZMN/50 Przetestowano w Firefox24
m93a

Odpowiedzi:

51

ZAKTUALIZOWANO: 19.02.2016

Uważaj tę odpowiedź za nieaktualną. Informacje na temat nowszej wersji przeglądarki znajdują się w innych odpowiedziach w tym poście.


Zasadniczo odroczenie mówi przeglądarce, aby poczekała „aż będzie gotowy” przed wykonaniem javascript w tym bloku skryptu. Zwykle dzieje się to po zakończeniu ładowania DOM i document.readyState == 4

Odroczony atrybut jest specyficzny dla przeglądarki internetowej. W przeglądarce Internet Explorer 8 w systemie Windows 7 wynik, który widzę na stronie testowej JS Fiddle, to 1–2–3.

Wyniki mogą się różnić w zależności od przeglądarki.

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

Wbrew powszechnemu przekonaniu IE częściej stosuje standardy niż ludzie, w rzeczywistości atrybut „odroczenia” jest zdefiniowany w specyfikacji DOM Level 1 http://www.w3.org/TR/REC-DOM-Level-1/level -one-html.html

Definicja odroczenia W3C: http://www.w3.org/TR/REC-html40/interact/scripts.html#adef-defer :

„Po ustawieniu ten atrybut logiczny daje wskazówkę dla agenta użytkownika, że ​​skrypt nie będzie generował żadnej zawartości dokumentu (np. Brak„ document.write ”w javascript), a zatem agent użytkownika może kontynuować parsowanie i renderowanie.”

Mark At Ramp51
źródło
8
@ MarkAtRamp51 - Jeśli twoja odpowiedź jest nieaktualna, powinieneś ją edytować zamiast narzekać na opinie negatywne w komentarzach do innych odpowiedzi. Komentarze negatywne dotyczą odpowiedzi, które „nie są przydatne”.
Christian Conkle
10
@ChristianConkle Doceniam lekcję etykiety, jednak inne odpowiedzi tutaj są aktualne. Mówiłem o tym, że w chwili zadawania pytania nie wybrano złej odpowiedzi. Być może powinieneś pilnować ludzi rozpowszechniających fałszywe oceny na temat społeczności niewłaściwie wybierających odpowiedzi, zamiast próbować przypominać ludziom, że rzeczy zmieniają się w czasie, a kontekst jest ważny. Nie widzę wartości w usuwaniu mojej odpowiedzi, ponieważ informacje historyczne są również cenne.
Mark At Ramp51
3
„Nie widzę wartości w usuwaniu mojej odpowiedzi, ponieważ informacje historyczne są również cenne”. W takim razie, co powiesz na dodanie notatki na początku, wskazującej, że ma ona zastosowanie tylko do wersji wcześniejszej niż HTML5, a następnie link do „poprawnej” ( aktualna) odpowiedź? To powinno zaoszczędzić ci wielu kłopotów (mówienie jako facet, który również raz zaakceptował „złą” odpowiedź i był pod presją rówieśników, by w końcu ją zmienić).
mgibsonbr,
3
@Leo to nie powinno być oflagowane? Wyszukiwanie „html5 defer script” to trzeci wynik w Google. Ta odpowiedź dostarcza wielu użytkownikom nieaktualnej i niepoprawnej definicji. (Obecna definicja: „Wskazuje, że agent użytkownika może odroczyć przetwarzanie skryptu. Zobacz definicję atrybutu odroczenia w HTML 4.0.”).
Malavos,
2
@ MarkAtRamp51 Myślę, że powinieneś zaktualizować swoją odpowiedź. Każdy, kto znajdzie to pytanie, a więc odpowiedź, nie rozpozna informacji historycznych. Będzie im to wyglądać tak, jakby to była poprawna odpowiedź. Tak działa Internet. Powinieneś więc zredagować swoją odpowiedź, pamiętać, że dawno była poprawna i odnieść się do poprawnej odpowiedzi.
Juuro,
167

Kilka fragmentów ze specyfikacji HTML5: http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

Nie można określić atrybutów odroczenia i asynchronizacji, jeśli atrybut src nie jest obecny.


Istnieją trzy możliwe tryby, które można wybrać za pomocą tych atrybutów [asynchronizuj i odraczaj]. Jeśli atrybut async jest obecny, skrypt zostanie wykonany asynchronicznie, gdy tylko będzie dostępny. Jeśli atrybut asynchroniczny nie jest obecny, ale atrybut odroczony jest obecny, skrypt jest wykonywany, gdy strona zakończy parsowanie. Jeśli żaden atrybut nie jest obecny, skrypt jest pobierany i wykonywany natychmiast, zanim agent użytkownika będzie kontynuował parsowanie strony.


Dokładne szczegóły przetwarzania tych atrybutów są, z powodów głównie historycznych, nieco nietrywialne i obejmują wiele aspektów HTML. Wymagania implementacyjne są zatem z konieczności rozproszone w całej specyfikacji. Poniższe algorytmy (w tej sekcji) opisują rdzeń tego przetwarzania, ale te algorytmy odnoszą się do nich i są do nich odwoływane reguły analizy dla znaczników początku i końca skryptu w HTML, w obcej treści oraz w XML, reguły dla document.write (), obsługa skryptów itp.


Jeśli element ma atrybut src, a element ma atrybut odroczenia, a element został oflagowany jako „wstawiony przez analizator składni”, a element nie ma atrybutu async:

Element należy dodać na końcu listy skryptów, które zostaną wykonane, gdy dokument zakończy parsowanie skojarzone z Dokumentem analizatora składni, który utworzył element.

Alohci
źródło
37
Być może moja odpowiedź tutaj powstrzyma ludzi od głosowania na moją odpowiedź z powodu twojego nieprzydatnego komentarza. Przyjęta odpowiedź nie jest zła, odpowiedź jest inna, ponieważ na początku 2011 r. Specyfikacja HTML5 była mniej istotna dla głównych przeglądarek internetowych niż obecnie. Ta odpowiedź może być lepsza w przyszłości, ale przyjęta odpowiedź nie jest NIEPRAWIDŁOWA .
Mark At Ramp51
3
Chociaż warto wiedzieć, co mówi specyfikacja, okazuje się, że niektóre przeglądarki, takie jak IE <9, deferźle się implementują . Jeśli używasz defer, nie możesz polegać na plikach skryptów wykonywanych po kolei w niektórych przeglądarkach.
Flimm,
2
@Flimm Nie tylko IE, wydaje się, że kolejność wykonania nie jest gwarantowana w Firefox .
Franklin Yu
Pierwszy cytat nie jest już ważny, prawda? Teraz mogę przeczytać: „Atrybutu nie można podać, jeśli atrybut src nie jest obecny lub jeśli skrypt nie jest klasycznym skryptem”. A klasyczny skrypt również nie zawiera src = "".
Félix Sanz
158

Prawdziwa odpowiedź brzmi: ponieważ nie możesz ufać odroczeniu.

W koncepcji odroczenia i asynchronizacji różnią się w następujący sposób:

async pozwala na pobranie skryptu w tle bez blokowania. Następnie, w momencie zakończenia pobierania renderowanie jest blokowane i skrypt jest wykonywany. Renderowanie zostanie wznowione po wykonaniu skryptu.

odroczenie robi to samo, z wyjątkiem roszczeń gwarantujących, że skrypty będą wykonywane w kolejności, w jakiej zostały określone na stronie, i że zostaną wykonane po zakończeniu analizy dokumentu. Dlatego niektóre skrypty mogą zakończyć pobieranie, a następnie usiąść i czekać na skrypty, które zostały pobrane później, ale pojawiły się przed nimi.

Niestety, ze względu na to, co tak naprawdę jest standardową walką kotów, definicja odroczenia różni się w zależności od specyfikacji, a nawet w najnowszych specyfikacjach nie daje użytecznej gwarancji. Jak pokazują odpowiedzi tutaj i ten problem , przeglądarki implementują odraczanie w inny sposób:

  • W niektórych sytuacjach niektóre przeglądarki mają błąd, który powoduje, że deferskrypty nie działają.
  • Niektóre przeglądarki opóźniają DOMContentLoadedzdarzenie do momentu deferzaładowania skryptów, a niektóre nie.
  • Niektóre przeglądarki stosują defersię do <script>elementów z wbudowanym kodem i bez srcatrybutu, a niektóre go ignorują.

Na szczęście specyfikacja przynajmniej określa, że ​​asynchronizacja zastępuje odroczenie. Możesz więc traktować wszystkie skrypty jako asynchroniczne i uzyskać szeroki wachlarz obsługi przeglądarki w następujący sposób:

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

98% przeglądarek używanych na całym świecie i 99% w USA uniknie blokowania przy takim podejściu.

(Jeśli musisz poczekać, aż dokument się zakończy parsowanie, wysłuchaj zdarzenia DOMContentLoadedzdarzenia lub skorzystaj z przydatnej .ready()funkcji jQuery . Chciałbyś to zrobić i tak, aby deferw pełni zrezygnować z przeglądarki, która w ogóle się nie implementuje ).

Chris Moschini
źródło
13
Dzięki, twoja odpowiedź była dla mnie najbardziej pomocna!
markus 12.12
5
Uważam, że to jest nieprawidłowe Zaletą odroczenia jest to, że nie jest wykonywane, dopóki parsowanie strony nie zostanie zakończone. Ta strona ma dobry wygląd,
tinkerr
1
@tinkerr W koncepcji masz rację; w praktyce nie okazuje się to prawdą. Ponieważ nie jest konsekwentnie wdrażany, gwarancja sekwencji nie jest uniwersalna, a zatem nie jest gwarancją. Przy wdrażaniu czegoś zależy Ci na wykonaniu. Cel projektu jest uroczy, ale niezbyt pomocny.
Chris Moschini
Chciałem tylko zaznaczyć, że Opera obsługuje ten deferatrybut od wersji 15 , która została wydana 2 czerwca 2013 r .
1
@VikasBansal Dla starszych przeglądarek, które nie obsługują asynchronizacji - czyli starszych IE.
Chris Moschini,
13

defermoże być użyty tylko w <script>tagu do włączenia zewnętrznego skryptu . Dlatego zaleca się stosowanie w <script>tagach w sekcji <head>.

Rajesh Paul
źródło
8

Jako atrybut odroczenia działa tylko ze znacznikiem scripts z src. Znaleziono sposób naśladowania odroczenia dla skryptów wbudowanych. Użyj zdarzenia DOMContentLoaded.

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

Jest tak, ponieważ zdarzenie DOMContentLoaded jest uruchamiane po całkowitym załadowaniu odroczonych skryptów przypisanych.

Bijoy Anupam
źródło
6

Atrybut odroczenia dotyczy tylko zewnętrznych skryptów (należy go używać tylko wtedy, gdy występuje atrybut src).

Soumitra
źródło
4

Zapoznaj się z tym doskonałym artykułem. Zanurz się w mętnych wodach ładowania skryptów przez programistę Google, Jake'a Archibalda z 2013 roku.

Cytując odpowiednią sekcję z tego artykułu:

Odraczać

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

Spec mówi : Pobierz razem, wykonaj w kolejności tuż przed DOMContentLoaded. Zignoruj ​​„odrocz” w skryptach bez „src”.

IE <10 mówi : Mogę wykonać 2.js w połowie wykonania 1.js. Czy to nie zabawne?

Przeglądarki w kolorze czerwonym mówią : nie mam pojęcia, co to za „odroczenie”, załaduję skrypty, jakby ich tam nie było.

Inne przeglądarki mówią : Ok, ale nie mogę ignorować „odroczenia” w skryptach bez „src”.

(Dodam, że wczesne wersje Firefox wyzwalają DOMContentLoaded, zanim deferskrypty zakończą działanie, zgodnie z tym komentarzem ).

Wygląda na to, że współczesne przeglądarki działają asyncpoprawnie, ale musisz działać poprawnie, gdy skrypty działają nieprawidłowo i być może przed DOMContentLoaded.

Flimm
źródło
1

Ten atrybut boolowski jest ustawiony tak, aby wskazywał przeglądarce, że skrypt ma zostać wykonany po przeanalizowaniu dokumentu. Ponieważ ta funkcja nie została jeszcze zaimplementowana we wszystkich innych głównych przeglądarkach, autorzy nie powinni zakładać, że wykonanie skryptu zostanie odroczone. Nigdy nie wywoływaj document.write () ze skryptu odroczonego (od Gecko 1.9.2 spowoduje to zniszczenie dokumentu). Atrybutu odroczenia nie należy używać w skryptach, które nie mają atrybutu src. Od wersji Gecko 1.9.2 atrybut odroczenia jest ignorowany w skryptach, które nie mają atrybutu src. Jednak w Gecko 1.9.1 nawet wbudowane skrypty są odraczane, jeśli ustawiony jest atrybut odroczenia.

defer działa z Chrome, Firefox, tj.> 7 i Safari

ref: https://developer.mozilla.org/en-US/docs/HTML/Element/script

s-sharma
źródło
0

Odroczony atrybut jest atrybutem boolowskim.

Gdy jest obecny, określa, że ​​skrypt jest wykonywany, gdy strona zakończy parsowanie.

Uwaga: Atrybut odroczenia dotyczy tylko skryptów zewnętrznych (należy go używać tylko wtedy, gdy występuje atrybut src).

Uwaga: Istnieje kilka sposobów wykonania zewnętrznego skryptu:

Jeśli async jest obecny: skrypt jest wykonywany asynchronicznie z resztą strony (skrypt zostanie wykonany, gdy strona będzie kontynuowała parsowanie) Jeśli asynchronia nie jest dostępna, a odroczenie jest obecne: skrypt jest wykonywany, gdy strona zakończy parsowanie Jeśli nie występuje ani asynchronizacja, ani odroczenie: skrypt jest pobierany i wykonywany natychmiast, zanim przeglądarka będzie dalej analizować stronę

srikanth_k
źródło