Tag Skrip - async & tunda

548

Saya punya beberapa pertanyaan tentang atribut async& deferuntuk <script>tag yang menurut saya hanya berfungsi di browser HTML5.

Salah satu situs saya memiliki dua file JavaScript eksternal yang saat ini berada tepat di atas </body>tag; yang pertama adalah bersumber dari google dan yang kedua adalah skrip eksternal lokal.

Sehubungan dengan kecepatan memuat situs

  1. Apakah ada keuntungan dalam menambahkan asyncke dua skrip yang saya miliki di bagian bawah halaman?

  2. Apakah akan ada keuntungan dalam menambahkan asyncopsi ke dua skrip dan meletakkannya di bagian atas halaman di <head>?

  3. Apakah ini berarti mereka mengunduh ketika halaman dimuat?
  4. Saya berasumsi ini akan menyebabkan penundaan untuk browser HTML4, tetapi apakah ini mempercepat pemuatan halaman untuk browser HTML5?

Menggunakan <script defer src=...

  1. Akankah memuat dua skrip di dalam <head>dengan atribut deferyang sama mempengaruhi seperti memiliki skrip sebelumnya </body>?
  2. Sekali lagi saya menganggap ini akan memperlambat browser HTML4.

Menggunakan <script async src=...

Jika saya memiliki dua skrip dengan asyncdiaktifkan

  1. Apakah mereka akan mengunduh secara bersamaan?
  2. Atau satu per satu dengan sisa halaman?
  3. Apakah urutan skrip kemudian menjadi masalah? Misalnya satu skrip tergantung pada skrip lain sehingga jika salah satu mengunduh lebih cepat, skrip kedua mungkin tidak dijalankan dengan benar, dll.

Akhirnya apakah saya lebih baik meninggalkan hal-hal sebagaimana adanya sampai HTML5 lebih umum digunakan?

Adam
sumber
5
asyncbaru (ish), tetapi defertelah menjadi bagian dari IE sejak IE4. defertelah ditambahkan ke browser lain jauh lebih baru, tetapi versi yang lebih lama dari browser tersebut cenderung kurang banyak berkeliaran.
Alohci
3
Sekarang, HTML5 telah menjadi sangat populer!
sept08
2
defersama dengan menempatkan skrip di bagian bawah HTML, yang sudah umum selama bertahun-tahun.
vsync
1
@vsync belum tentu benar, browser akan mengunduh JS dengan tag penangguhan saat mem-parsing tag skrip, tetapi akan menunda pengerjaan sampai tepat sebelum DOMContentLoaded. Pengunduhan bukan pemblokiran. Menempatkan di bagian bawah HTML akan menunda pengunduhan dan pelaksanaan JS hingga DOM dibuat, tetapi Anda masih akan mengalami penundaan tambahan dengan menunggu pengunduhan.
Brad Frost
@BradFrost - Mengunduh menghalangi dalam pandangan saya, dalam arti ia mengambil bandwidth internet, dan bagi mereka yang memiliki koneksi lambat, saya melihatnya sebagai keharusan untuk memuat dokumen terlebih dahulu dan hanya kemudian, ketika telah diberikan, mulai mengunduh file javascript . Ini berlaku dalam kasus di mana konten tidak digabungkan dengan javascript untuk merender semuanya (seperti SPA )
vsync

Jawaban:

406

Simpan skrip Anda tepat sebelumnya </body>. Async dapat digunakan dengan skrip yang berlokasi di sana dalam beberapa keadaan (lihat diskusi di bawah). Tunda tidak akan membuat banyak perbedaan untuk skrip yang terletak di sana karena pekerjaan parsing DOM sudah cukup banyak dilakukan.

Berikut adalah artikel yang menjelaskan perbedaan antara async dan defer: http://peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/ .

HTML Anda akan ditampilkan lebih cepat di peramban yang lebih lama jika Anda menyimpan skrip di ujung badan tepat sebelumnya </body>. Jadi, untuk menjaga kecepatan muat di browser lama, Anda tidak ingin meletakkannya di tempat lain.

Jika skrip kedua Anda bergantung pada skrip pertama (mis. Skrip kedua Anda menggunakan jQuery yang dimuat dalam skrip pertama), maka Anda tidak dapat membuatnya async tanpa kode tambahan untuk mengontrol urutan eksekusi, tetapi Anda dapat membuatnya menunda karena skrip penundaan akan masih dieksekusi dalam urutan, tidak sampai dokumen diurai. Jika Anda memiliki kode itu dan Anda tidak perlu menjalankan skrip segera, Anda dapat membuatnya async atau menunda.

Anda dapat memasukkan skrip ke dalam <head>tag dan mengaturnya deferdan memuat skrip akan ditangguhkan sampai DOM telah diuraikan dan itu akan mendapatkan tampilan halaman cepat di browser baru yang mendukung penundaan, tetapi itu tidak akan membantu Anda sama sekali di browser yang lebih lama dan itu tidak benar-benar lebih cepat daripada hanya menempatkan skrip tepat sebelum </body>yang bekerja di semua browser. Jadi, Anda bisa melihat mengapa lebih baik meletakkannya sebelumnya </body>.

Async lebih berguna ketika Anda benar-benar tidak peduli ketika skrip dimuat dan tidak ada yang tergantung pada pengguna tergantung pada pemuatan skrip itu. Contoh yang paling sering dikutip untuk menggunakan async adalah skrip analitik seperti Google Analytics yang tidak Anda inginkan menunggu dan itu tidak mendesak untuk segera dijalankan dan itu berdiri sendiri sehingga tidak ada yang bergantung padanya.

Biasanya pustaka jQuery bukan kandidat yang baik untuk async karena skrip lain bergantung padanya dan Anda ingin menginstal event handler sehingga halaman Anda dapat mulai merespons acara pengguna dan Anda mungkin perlu menjalankan beberapa kode inisialisasi berbasis jQuery untuk menetapkan status awal halaman. Ini dapat digunakan async, tetapi skrip lain harus dikodekan untuk tidak mengeksekusi sampai jQuery dimuat.

pacar00
sumber
8
Tunda harus menjalankannya secara berurutan, tetapi jalankan sebelum dom-contentloaded. Bukankah itu berarti meletakkannya di kepala akan lebih cepat, karena dapat mulai mengunduhnya SEBELUM Tubuh html diuraikan?
Kevin
9
Anda bilang memasukkan skrip ke dalam headdan mengaturnya defertidak akan lebih cepat daripada menempatkannya sebelumnya </body>, tetapi dari apa yang saya baca itu salah. Pikirkan tentang hal ini - jika Anda memasukkan skrip ke dalamnya <head>, maka skrip tersebut akan segera mulai diunduh, sedangkan jika skrip itu benar sebelumnya, </body>maka semua elemen lainnya akan diunduh terlebih dahulu.
Nate
12
@Nate - Ini tidak akan membuat dokumen Anda memuat lebih cepat yang merupakan poin saya. Anda benar bahwa itu dapat meningkatkan memuat skrip lebih cepat, tetapi juga dapat memperlambat pemuatan dokumen dan isinya karena Anda menggunakan beberapa bandwidth Anda dan menggunakan salah satu koneksi terbatas yang browser akan buat ke server yang diberikan untuk muat skrip saat sedang mencoba memuat konten Anda.
jfriend00
4
"Jika skrip kedua Anda bergantung pada skrip pertama ... maka Anda tidak dapat membuatnya skrip async atau penundaan" - itu tidak benar, dengan penundaan yang mereka lakukan secara berurutan.
DisgruntledGoat
2
Pada titik ini, persyaratan </body> tidak terlalu diperlukan dengan pengembangan browser sejak 2012 ketika jawaban ini diposting
bgcode
845

Gambar ini menjelaskan tag skrip normal, async, dan penundaan

masukkan deskripsi gambar di sini

  • Skrip async dieksekusi segera setelah skrip dimuat, jadi skrip tersebut tidak menjamin urutan eksekusi (skrip yang Anda sertakan di bagian akhir dapat dieksekusi sebelum file skrip pertama)

  • Skrip penangguhan menjamin urutan eksekusi di mana mereka muncul di halaman.

Ref tautan ini: http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html

Prasanth Bendra
sumber
Saya pikir contoh dengan banyak skrip akan lebih baik untuk menggambarkan urutan mereka
vsync
4
@writofmandamus Sepertinya asyncakan menang. Lihat stackoverflow.com/questions/13821151/…
Monsignor
Terima kasih atas penjelasannya. Namun, gambar tidak untuk skala. Jika hanya pada <script>tag, total panjang halaman memuat lebih lama dari waktu yang dibutuhkan untuk mengunduh file skrip.
arni
@ BhavikHirani Menurut situs ini , menggunakan async dan menunda dalam tag skrip yang sama menggunakan async jika browser mendukungnya, atau kembali untuk menunda jika tidak mendukung async, tetapi mendukung penundaan. Perilaku ini sangat berbeda, jadi saya tidak akan menyarankan menggunakan keduanya, karena hasilnya tidak dapat diprediksi dan dapat menjadi sumber yang bagus untuk bug.
Adrian Wiik
@arni Hanya jika bandwidth digunakan sepenuhnya, yang jarang. Dan kedua unduhan akan berbagi bandwidth, bukan memblokir satu. — Selanjutnya: gambar-gambar ini menunjukkan parsing berwarna hijau, bukan unduhan.
Robert Siemer
213

HTML5: async,defer

Di HTML5, Anda bisa memberi tahu browser kapan harus menjalankan kode JavaScript. Ada 3 kemungkinan:

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

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

<script defer src="myscript.js"></script>
  1. Tanpa asyncatau defer, browser akan segera menjalankan skrip Anda, sebelum merender elemen yang ada di bawah tag skrip Anda.

  2. Dengan async(asinkron), browser akan terus memuat halaman HTML dan merendernya saat browser memuat dan menjalankan skrip pada saat yang sama.

  3. Dengan defer, browser akan menjalankan skrip Anda ketika halaman selesai parsing. (tidak perlu selesai mengunduh semua file gambar. Ini bagus.)

Dinesh
sumber
Diperlukan templat blogger.com async=""sebelum akan memvalidasi dan menyimpan perubahan templat.
noobninja
1
Catatan: tidak ada jaminan bahwa skrip akan berjalan dalam urutan yang ditentukan menggunakan Async. "Jadi, jika skrip kedua tergantung pada skrip pertama, hindari Async."
Faisal Naseer
2
async- Skrip dieksekusi saat mereka telah diunduh, tanpa mempertimbangkan urutannya dalam file HTML.
vsync
30

Keduanya asyncdan deferskrip mulai mengunduh segera tanpa menjeda pengurai dan keduanya mendukung onloadpenangan opsional untuk mengatasi kebutuhan umum untuk melakukan inisialisasi yang tergantung pada skrip.

Perbedaan antara asyncdan deferberpusat di sekitar saat skrip dieksekusi. Setiap asyncskrip dieksekusi pada kesempatan pertama setelah selesai mengunduh dan sebelum acara pemuatan jendela. Ini berarti ada kemungkinan (dan kemungkinan) bahwa asyncskrip tidak dieksekusi dalam urutan di mana mereka muncul di halaman. Sedangkan deferscript, di sisi lain, dijamin akan dieksekusi dalam urutan yang terjadi di halaman. Eksekusi itu dimulai setelah penguraian selesai, tetapi sebelum acara dokumen DOMContentLoaded.

Sumber & perincian lebih lanjut: di sini .

Zameer Khan
sumber
25

Menghadapi masalah yang sama dan sekarang jelas mengerti bagaimana keduanya akan bekerja. Semoga tautan referensi ini akan membantu ...

Async

Saat Anda menambahkan atribut async ke tag skrip Anda, hal berikut akan terjadi.

<script src="myfile1.js" async></script>
<script src="myfile2.js" async></script>
  1. Buat permintaan paralel untuk mengambil file.
  2. Terus parsing dokumen seolah-olah tidak pernah terputus.
  3. Jalankan masing-masing skrip saat file diunduh.

Menunda

Defer sangat mirip dengan async dengan satu perbedaan besar. Inilah yang terjadi ketika browser menemukan skrip dengan atribut penangguhan.

<script src="myfile1.js" defer></script>
<script src="myfile2.js" defer></script>
  1. Buat permintaan paralel untuk mengambil file individual.
  2. Terus parsing dokumen seolah-olah tidak pernah terputus.
  3. Selesaikan penguraian dokumen meskipun file skrip telah diunduh.
  4. Jalankan setiap skrip sesuai urutan yang ditemukan dalam dokumen.

Referensi: Perbedaan antara Async dan Defer

kamesh
sumber
7

asyncdan deferakan mengunduh file selama parsing HTML. Keduanya tidak akan mengganggu pengurai.

  • Script dengan asyncatribut akan dieksekusi setelah diunduh. Sedangkan script dengan deferatribut akan dieksekusi setelah menyelesaikan parsing DOM.

  • Skrip yang dimuat dengan asynctidak menjamin pesanan apa pun. Sementara skrip yang dimuat dengan deferatribut mempertahankan urutan di mana mereka muncul di DOM.

Gunakan <script async>saat skrip tidak bergantung pada apa pun. ketika skrip tergantung penggunaan.

Solusi terbaik adalah menambahkan bagian bawah tubuh. Tidak akan ada masalah dengan pemblokiran atau rendering.

NavyaKumar
sumber
Hanya ingin membuat klarifikasi di sini, ada dua hal yang terjadi di sini 1. Mengunduh sumber daya 2. Mengeksekusi sumber daya. Pengunduhan sumber daya dalam kedua kasus (async dan penundaan) tidak memblokir, artinya, mereka tidak memblokir penguraian html, sementara eksekusi di async memblokir penguraian dan dalam kasus penundaan, eksekusi terjadi setelah markup html diuraikan, karenanya tidak menghalangi dalam hal ini.
pOoOf
5

Saya pikir Jake Archibald memberi kami beberapa wawasan pada tahun 2013 yang mungkin menambah lebih positif pada topik:

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

Cawan suci memiliki set unduhan skrip segera tanpa memblokir rendering dan mengeksekusi sesegera mungkin dalam urutan mereka ditambahkan. Sayangnya HTML membenci Anda dan tidak akan membiarkan Anda melakukannya.

(...)

Jawabannya sebenarnya dalam spesifikasi HTML5, meskipun tersembunyi di bagian bawah bagian pemuatan skrip. " Atribut async IDL mengontrol apakah elemen akan menjalankan asynchronous atau tidak. Jika flag" force-async "elemen diatur, maka, pada saat mendapatkan, atribut IDL async harus mengembalikan true, dan pada pengaturan," force-async " bendera harus terlebih dahulu tidak disetel ... ".

(...)

Script yang dibuat secara dinamis dan ditambahkan ke dokumen async secara default , mereka tidak memblokir rendering dan mengeksekusi segera setelah mereka unduh, yang berarti mereka bisa keluar dalam urutan yang salah. Namun, kami dapat secara eksplisit menandainya sebagai bukan asinkron:

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

Ini memberi skrip kami campuran perilaku yang tidak dapat dicapai dengan HTML biasa. Dengan secara eksplisit bukan async, skrip ditambahkan ke antrian eksekusi, antrian yang sama dengan yang ditambahkan ke dalam contoh HTML-polos pertama kami. Namun, dengan dibuat secara dinamis, mereka dieksekusi di luar parsing dokumen, jadi rendering tidak diblokir saat diunduh (jangan bingung memuat skrip tidak-async dengan sinkronisasi XHR, yang tidak pernah merupakan hal yang baik).

Script di atas harus dimasukkan secara inline di bagian atas halaman, antrian unduhan skrip sesegera mungkin tanpa mengganggu rendering progresif, dan dieksekusi sesegera mungkin dalam urutan yang Anda tentukan. “2.js” bebas untuk diunduh sebelum “1.js”, tetapi itu tidak akan dijalankan sampai “1.js” berhasil diunduh dan dieksekusi, atau gagal melakukan keduanya. Hore! async-download tetapi memerintahkan-eksekusi !

Namun, ini mungkin bukan cara tercepat untuk memuat skrip:

(...) Dengan contoh di atas browser harus mengurai dan mengeksekusi skrip untuk menemukan skrip yang akan diunduh. Ini menyembunyikan skrip Anda dari preload scanner. Peramban menggunakan pemindai ini untuk menemukan sumber daya pada halaman yang akan Anda kunjungi berikutnya, atau menemukan sumber daya halaman saat parser diblokir oleh sumber daya lain.

Kami dapat menambahkan penemuan kembali dengan menempatkan ini di kepala dokumen:

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

Ini memberitahu browser bahwa halaman membutuhkan 1.js dan 2.js. tautan [rel = subresource] mirip dengan tautan [rel = prefetch], tetapi dengan semantik yang berbeda. Sayangnya saat ini hanya didukung di Chrome, dan Anda harus menyatakan skrip mana yang akan dimuat dua kali, sekali melalui elemen tautan, dan sekali lagi di skrip Anda.

Koreksi: Saya awalnya menyatakan ini diambil oleh pemindai preload, tidak, diambil oleh parser biasa. Namun, preload scanner bisa mengambil ini, hanya saja belum, sedangkan skrip yang dimasukkan oleh kode yang dapat dieksekusi tidak pernah dapat dimuat sebelumnya. Terima kasih kepada Yoav Weiss yang mengoreksi saya di komentar.

mjfneto
sumber
1

Tampaknya perilaku defer dan async bergantung pada browser, setidaknya pada fase eksekusi. CATATAN, penundaan hanya berlaku untuk skrip eksternal. Saya berasumsi async mengikuti pola yang sama.

Di IE 11 dan di bawah, urutannya tampak seperti ini:

  • async (sebagian dapat dijalankan saat memuat halaman)
  • tidak ada (bisa dieksekusi saat memuat halaman)
  • tunda (dijalankan setelah halaman dimuat, semua tunda dalam urutan penempatan dalam file)

Di Edge, Webkit, dll, atribut async tampaknya diabaikan atau ditempatkan di akhir:

  • data-pagespeed-no-defer (dijalankan sebelum skrip lain, saat halaman dimuat)
  • tidak ada (bisa dieksekusi saat halaman sedang memuat)
  • tunda (tunggu sampai DOM dimuat, semua tunda dalam urutan penempatan dalam file)
  • async (tampaknya menunggu sampai DOM dimuat)

Di browser yang lebih baru, atribut data-pagespeed-no-defer berjalan sebelum skrip eksternal lainnya. Ini untuk skrip yang tidak bergantung pada DOM.

CATATAN: Gunakan tunda ketika Anda membutuhkan urutan eksekusi skrip eksternal Anda. Ini memberi tahu browser untuk menjalankan semua skrip yang ditangguhkan dengan urutan penempatan dalam file.

ASIDE: Ukuran javascripts eksternal memang penting saat memuat ... tetapi tidak berpengaruh pada urutan eksekusi.

Jika Anda khawatir tentang kinerja skrip Anda, Anda mungkin ingin mempertimbangkan minifikasi atau hanya memuatnya secara dinamis dengan XMLHttpRequest.

Charles Owen
sumber
data-pagespeed-no-deferadalah atribut yang digunakan oleh modul PageSpeed sisi server . The atribut dengan sendirinya tidak memiliki efek di browser apapun. data-pagespeed-no-defer
Qtax