Bagaimana tepatnya <script defer = "defer"> bekerja?

208

Saya memiliki beberapa <script>elemen, dan kode di dalamnya tergantung pada kode di <script>elemen lain . Saya melihat deferatribut dapat berguna di sini karena memungkinkan blok kode ditunda dalam eksekusi.

Untuk mengujinya saya menjalankan ini di Chrome: http://jsfiddle.net/xXZMN/ .

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

Namun, itu peringatan 2 - 1 - 3. Kenapa tidak disiagakan 1 - 2 - 3?

pimvdb
sumber
2
Mungkin lihat artikel ini . Dan, seperti biasa, IE memiliki pendapat mereka sendiri tentang apa artinya sesuatu dan memutuskan untuk memuat skrip terlebih dahulu tetapi menunda eksekusi sampai body dimuat (biasanya).
Brad Christie
Terima kasih, namun halaman pengujian memiliki hasil yang berbeda di Chrome: optimasi situs web.com/speed/tweak/defer/test . Tangkapan layar menunjukkan bagaimana saya mengharapkannya, sementara Chrome sepertinya mengeksekusi yang ditangguhkan terlebih dahulu.
pimvdb
1
Saya pikir Anda akan menemukan definisi IE tentang penundaan, cocok dengan niat W3C untuk menunda dalam spesifikasi DOM Level 1.
Mark At Ramp51
41
Seperti Alohci sudah menunjukkan dalam jawabannya, menurut Standar HTML defer hanya valid ketika menentukan src. Ini mungkin menjadi alasan mengapa contoh Anda tidak berfungsi seperti yang diharapkan di sebagian besar browser.
Pankrat
2
@Pratrat Kisah Nyata! Coba jsfiddle.net/xXZMN/50 Diuji di Firefox24
m93a

Jawaban:

51

DIPERBARUI: 2/19/2016

Anggap jawaban ini sudah usang. Lihat jawaban lain pada posting ini untuk informasi yang relevan dengan versi browser yang lebih baru.


Pada dasarnya, tunda memberitahu browser untuk menunggu "sampai siap" sebelum menjalankan javascript di blok skrip itu. Biasanya ini setelah DOM selesai memuat dan mendokumentasikan.readyState == 4

Atribut defer khusus untuk penjelajah internet. Di Internet Explorer 8, pada Windows 7 hasil yang saya lihat di halaman pengujian JS Fiddle Anda adalah, 1 - 2 - 3.

Hasil dapat bervariasi dari browser ke browser.

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

Bertentangan dengan kepercayaan populer, IE mengikuti standar lebih sering daripada yang dibiarkan orang, pada kenyataannya atribut "penangguhan" didefinisikan dalam spesifikasi DOM Level 1 http://www.w3.org/TR/REC-DOM-Level-1/level -one-html.html

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

"Ketika disetel, atribut boolean ini memberikan petunjuk kepada agen pengguna bahwa skrip tidak akan menghasilkan konten dokumen apa pun (misalnya, tidak ada" document.write "dalam javascript) dan dengan demikian, agen pengguna dapat melanjutkan penguraian dan rendering."

Tandai At Ramp51
sumber
8
@ MarkAtRamp51 - Jika jawaban Anda sudah kedaluwarsa, Anda harus mengeditnya alih-alih mengeluh tentang downvotes dalam komentar atas jawaban lain. Downvotes adalah untuk jawaban yang "tidak berguna."
Christian Conkle
10
@ChristianConkle Saya menghargai pelajaran etiket, namun jawaban lain di sini terkini. Saya membahas fakta bahwa jawaban yang salah tidak dipilih pada saat pertanyaan diajukan. Mungkin Anda harus mengawasi orang-orang yang menyebarkan penilaian salah tentang komunitas dengan memilih jawaban yang tidak tepat, alih-alih orang-orang yang berusaha mengingatkan orang bahwa banyak hal berubah seiring waktu, dan konteksnya penting. Saya tidak melihat nilai dalam menghapus jawaban saya karena informasi historis juga berharga.
Mark At Ramp51
3
"Saya tidak melihat nilai dalam menghapus jawaban saya karena informasi historis juga berharga" Dalam hal itu, bagaimana dengan menambahkan catatan di awal yang menunjukkan bahwa itu hanya berlaku untuk pra-HTML5, dan kemudian menautkan ke "benar" ( terbaru) menjawab? Itu akan menyelamatkan Anda dari banyak masalah (berbicara sebagai seorang pria yang juga memiliki jawaban "salah" diterima satu kali, dan "ditekan oleh teman" untuk akhirnya mengubahnya).
mgibsonbr
3
@ Leo, bukankah seharusnya ditandai? Dengan mencari "script penundaan html5" ini adalah hasil ketiga di google. Jawaban ini kemudian memberikan banyak pengguna definisi yang ketinggalan jaman dan, salah. (Definisi saat ini: "Menunjukkan bahwa agen pengguna dapat menunda pemrosesan skrip. Lihat definisi atribut menunda dalam HTML 4.0.").
Malavos
2
@ MarkAtRamp51Saya pikir Anda harus memperbarui jawaban Anda. Siapa pun yang menemukan pertanyaan ini dan jawaban Anda tidak akan mengenali informasi historisnya. Itu akan terlihat bagi mereka seperti itu adalah jawaban yang benar hari ini. Begitulah cara kerja internet. Jadi, Anda harus mengedit jawaban Anda, perhatikan bahwa itu benar sekali waktu, dan merujuk ke jawaban yang benar.
Juuro
167

Beberapa cuplikan dari spesifikasi HTML5: http://w3c.github.io/html/semantics-scripting.html#element-attrdef-script-async

Atribut defer dan async tidak boleh ditentukan jika atribut src tidak ada.


Ada tiga mode yang mungkin dapat dipilih menggunakan atribut-atribut ini [async and defer]. Jika atribut async hadir, maka skrip akan dijalankan secara tidak sinkron, segera setelah tersedia. Jika atribut async tidak ada tetapi atribut penangguhan hadir, maka skrip dieksekusi ketika halaman telah selesai diuraikan. Jika tidak ada atribut yang hadir, maka skrip diambil dan dieksekusi segera, sebelum agen pengguna terus mengurai halaman.


Rincian pemrosesan yang tepat untuk atribut ini, untuk sebagian besar alasan historis, agak tidak sepele, melibatkan sejumlah aspek HTML. Persyaratan implementasi oleh karena itu tersebar di seluruh spesifikasi. Algoritme di bawah ini (pada bagian ini) menjelaskan inti dari pemrosesan ini, tetapi algoritma ini merujuk dan dirujuk oleh aturan parsing untuk tag awal dan akhir skrip dalam HTML, dalam konten asing, dan dalam XML, aturan untuk dokumen tersebut. Menulis () metode, penanganan skrip, dll.


Jika elemen memiliki atribut src, dan elemen memiliki atribut penangguhan, dan elemen tersebut telah ditandai sebagai "parser-insert", dan elemen tersebut tidak memiliki atribut async:

Elemen harus ditambahkan ke akhir daftar skrip yang akan mengeksekusi ketika dokumen telah selesai parsing yang terkait dengan dokumen parser yang membuat elemen.

Alohci
sumber
37
Mungkin, tanggapan saya di sini akan menghentikan orang untuk tidak memilih jawaban saya, karena komentar Anda yang tidak membantu. Jawaban yang diterima tidak salah, jawabannya berbeda, karena pada awal 2011 spesifikasi HTML5 kurang relevan dengan pengiklan web arus utama daripada saat ini. Jawaban ini mungkin lebih baik diteruskan, tetapi jawaban yang diterima tidak salah dengan standar apa pun.
Mark At Ramp51
3
Meskipun berguna untuk mengetahui apa yang dikatakan oleh spec, ternyata beberapa browser seperti IE <9 mengimplementasikan dengan deferburuk . Jika Anda menggunakan defer, Anda tidak bisa mengandalkan file skrip yang sedang dieksekusi secara berurutan di beberapa browser.
Flimm
2
@ Flimm Bukan hanya IE, sepertinya urutan eksekusi juga tidak dijamin di Firefox .
Franklin Yu
Kutipan pertama sudah tidak berlaku lagi kan? Sekarang saya dapat membaca ini: "Atribut tidak boleh ditentukan jika atribut src tidak ada, atau jika skrip bukan skrip klasik.". Dan skrip klasik adalah skrip tanpa src = "" juga.
Félix Sanz
158

Jawaban sebenarnya adalah: Karena Anda tidak dapat mempercayai penundaan.

Dalam konsep, tunda dan async berbeda sebagai berikut:

async memungkinkan skrip untuk diunduh di latar belakang tanpa memblokir. Kemudian, saat selesai mengunduh, rendering diblokir dan skrip itu dijalankan. Render dilanjutkan ketika skrip telah dieksekusi.

menunda melakukan hal yang sama, kecuali klaim untuk menjamin bahwa skrip mengeksekusi dalam urutan yang ditentukan pada halaman, dan bahwa mereka akan dieksekusi setelah dokumen selesai parsing. Jadi, beberapa skrip mungkin selesai diunduh kemudian duduk dan tunggu skrip yang diunduh nanti tetapi muncul di depan mereka.

Sayangnya, karena apa yang sebenarnya merupakan pertarungan kucing standar, definisi defer bervariasi dari satu spesifikasi ke yang lainnya, dan bahkan dalam spesifikasi terbaru tidak menawarkan jaminan yang berguna. Seperti yang diperlihatkan jawaban di sini dan masalah ini , browser menerapkan penundaan dengan berbeda:

  • Dalam situasi tertentu beberapa browser memiliki bug yang menyebabkan deferskrip kehabisan urutan.
  • Beberapa browser menunda DOMContentLoadedacara sampai setelah deferskrip dimuat, dan beberapa tidak.
  • Beberapa browser taat deferpada <script>elemen dengan kode inline dan tanpa srcatribut, dan beberapa mengabaikannya.

Untungnya spec setidaknya menentukan bahwa async menimpa penundaan. Jadi, Anda dapat memperlakukan semua skrip sebagai async dan mendapatkan dukungan browser yang luas seperti:

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

98% browser yang digunakan di seluruh dunia dan 99% di AS akan menghindari pemblokiran dengan pendekatan ini.

(Jika Anda perlu menunggu sampai dokumen selesai diuraikan, dengarkan acara DOMContentLoadedacara atau gunakan .ready()fungsi jQuery yang praktis . Anda tetap ingin melakukan ini agar dapat kembali dengan anggun di peramban yang tidak menerapkan defersama sekali.)

Chris Moschini
sumber
13
Terima kasih, jawaban Anda adalah yang paling membantu saya!
markus
5
Saya percaya ini tidak benar. Manfaat dari penundaan adalah bahwa ia tidak mengeksekusi sampai penguraian halaman selesai. Halaman ini memiliki visual yang bagus untuk menjelaskan perbedaan antara async dan defer: peter.sh/experiments/…
tinkerr
1
@tinkerr Dalam konsep Anda benar; dalam praktiknya ini ternyata tidak benar. Karena tidak diterapkan secara konsisten, jaminan urutan tidak universal, dan karenanya, bukan jaminan. Saat menerapkan sesuatu yang Anda pedulikan eksekusi. Maksud desainnya lucu, tapi tidak terlalu membantu.
Chris Moschini
Hanya ingin menunjukkan bahwa Opera telah mendukung deferatribut tersebut sejak versi 15 , yang dirilis pada 2 Juni 2013 .
1
@VikasBansal Untuk browser lama yang tidak mendukung async - yaitu IE yang lebih lama.
Chris Moschini
13

deferhanya dapat digunakan dalam <script>tag untuk penyertaan skrip eksternal . Oleh karena itu disarankan untuk digunakan dalam -tag <script>di <head>-seksi.

Rajesh Paul
sumber
8

Karena atribut penangguhan hanya berfungsi dengan tag skrip dengan src. Menemukan cara untuk meniru penangguhan untuk skrip inline. Gunakan acara DOMContentLoaded.

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

Ini karena, peristiwa DOMContentLoaded diaktifkan setelah skrip yang ditangguhkan ditangguhkan sepenuhnya dimuat.

Bijoy Anupam
sumber
6

Atribut defer hanya untuk skrip eksternal (hanya boleh digunakan jika atribut src ada).

Soumitra
sumber
4

Lihat artikel yang luar biasa ini Menyelam dalam-dalam ke perairan keruh pemuatan skrip oleh pengembang Google Jake Archibald yang ditulis pada 2013.

Mengutip bagian yang relevan dari artikel itu:

Menunda

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

Spec mengatakan : Unduh bersama, jalankan secara berurutan tepat sebelum DOMContentLoaded. Abaikan "tunda" pada skrip tanpa "src".

IE <10 mengatakan : Saya mungkin menjalankan 2.js di tengah-tengah eksekusi 1.js. Bukankah itu menyenangkan ??

Browser berwarna merah mengatakan : Saya tidak tahu apa ini "penundaan", saya akan memuat skrip seolah-olah tidak ada.

Browser lain mengatakan : Oke, tapi saya mungkin tidak mengabaikan "menunda" pada skrip tanpa "src".

(Saya akan menambahkan bahwa versi awal pemicu Firefox DOMContentLoaded sebelum deferskrip selesai berjalan, menurut komentar ini .)

Peramban modern tampaknya mendukung asyncdengan benar, tetapi Anda harus OK dengan skrip yang tidak berjalan dengan baik dan mungkin sebelum DOMContentLoaded.

Flimm
sumber
1

Atribut Boolean ini diatur untuk menunjukkan ke browser bahwa skrip dimaksudkan untuk dieksekusi setelah dokumen diuraikan. Karena fitur ini belum diterapkan oleh semua browser utama lainnya, penulis tidak boleh berasumsi bahwa eksekusi skrip akan benar-benar ditangguhkan. Jangan pernah panggil document.write () dari skrip penundaan (karena Tokek 1.9.2, ini akan menerbangkan dokumen). Atribut defer tidak boleh digunakan pada skrip yang tidak memiliki atribut src. Sejak Gecko 1.9.2, atribut defer diabaikan pada skrip yang tidak memiliki atribut src. Namun, di Gecko 1.9.1 bahkan skrip inline ditangguhkan jika atribut defer diatur.

menunda bekerja dengan chrome, firefox, yaitu> 7 dan Safari

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

s-sharma
sumber
0

Atribut defer adalah atribut boolean.

Saat ada, itu menentukan bahwa skrip dieksekusi ketika halaman telah selesai parsing.

Catatan: Atribut defer hanya untuk skrip eksternal (hanya boleh digunakan jika atribut src ada).

Catatan: Ada beberapa cara skrip eksternal dapat dijalankan:

Jika async ada: Skrip dieksekusi secara tidak serempak dengan sisa halaman (skrip akan dieksekusi saat halaman melanjutkan parsing) Jika async tidak ada dan tunda hadir: Skrip dijalankan ketika halaman telah selesai parsing Jika async atau defer tidak ada: Skrip diambil dan dieksekusi segera, sebelum browser melanjutkan penguraian halaman

srikanth_k
sumber