Modern websitelerinde, genellikle scriptâler HTMLâden daha baskındır: scriptâlerin dosya/indirme boyutları büyüktür ve iÅlenme süreleri uzundur.
Tarayıcı, HTMLâi yüklerken <script>...</script> etiketiyle karÅılaÅtıÄında, DOMâu oluÅturmaya devam edemez. Böyle bir durumda scriptâi çalıÅtırmak zorundadır. Benzer durum <script src="..."></script> Åeklinde dıÅarıdan aktarılan scriptâler içinde geçerlidir: Tarayıcı script indirilene kadar bekleyecek, sonrasında onu çalıÅtıracak ve en sonunda sayfanın geri kalananı iÅleyecektir.
Bu durum iki önemli soruna yol açar:
- Scriptâler, onların altındaki DOM öÄelerini (element) göremeyebilir, yani iÅleyici fonksiyonlar (handlers) vb. ekleyemezsiniz.
- Sayfanın üst kısmında büyük bir script varsa, bu âsayfanın yüklenmesini engellerâ. Kullanıcılar, script indirilip, çalıÅtırılana kadar sayfa içeriÄini göremez.
<p>...script'ten önceki içerik...</p>
<script src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<!-- Bu, script yüklenene kadar gözükmeyecek -->
<p>...script'ten sonraki içerik...</p>
Bunun içi bazı geçici çözümler vardır. ÃrneÄin, scriptâi sayfanın alt kısmına yerleÅtirebiliriz. Bu sayede script, kendinden önce bulunan öÄeleri görebilir ve sayfa içeriÄinin görüntülenmesini engellemez:
<body>
...tüm içerik script'in üzerindedir...
<script src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
</body>
Fakat bu çözüm mükemmel olmaktan uzaktır. ÃrneÄin, tarayıcı, scriptâi HTML belgesinin tamamını indirdikten sonra farkeder (ve onu indirmeye baÅlayabilir). Uzun HTML belgelesi için, bu fark edilebilir bir gecikme olabilir.
Bu tür durumlar çok hızlı bir internet baÄlantısına sahip olanlar için önemsizdir, fakat dünyada birçok insan hala yavaÅ bir internet hızına sahip ve mükemmel olmaktan uzak olan mobil interneti kullanıyor.
Neyse ki, bizim için bu sorunu çözen iki tane <script> niteliÄi (attribute) vardır: defer ve async.
defer
defer niteliÄi, tarayıcıya sayfayı yüklemeye devam etmesini, ve scriptâin âarkaplandaâ yüklemesini, sonrasında sayfa yüklendikten sonra scriptâin çalıÅtırılmasını söyler.
Yukarıdaki ile aynı örnek, fakat burada defer niteliÄi mevcut:
<p>...script'lerden önceki içerik...</p>
<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<!-- hemen görülebilir -->
<p>...script'lerden sonraki içerik...</p>
deferkullanılan script, sayfayı engellemez.deferkullanılan script, her zaman DOM hazır olduÄunda,DOMContentLoadedolayından (event) önce çalıÅtırılır.
AÅaÄıdaki örnek bunu göstermektedir:
<p>...script'lerden önceki içerik...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("DOM ertelemeden (defer) sonra hazır!")); // (2)
</script>
<script defer src="https://javascript.info/article/script-async-defer/long.js?speed=1"></script>
<p>...script'lerden sonraki içerik...</p>
- Sayfa içeriÄi hemen görünür.
DOMContentLoaded, ertelenmiÅ (deferred) scriptâi bekler. Sadece script(2)indirilip, çalıÅtırıldıÄında tetiklenir.
ErtelenmiÅ scriptâler (deferred scripts), tıpkı normal scriptâler gibi göreli sıralarını korurlar.
Yani, ilk olarak büyük bir scriptâe ve sonrasında küçük bir tanesine sahipsek, sonuncusu bekler.
<script defer src="https://javascript.info/article/script-async-defer/long.js"></script>
<script defer src="https://javascript.info/article/script-async-defer/small.js"></script>
Tarayıcılar, performansı artırmak için sayfadaki komut dosyalarını tarar ve paralel/eÅ zamanlı olarak indirmeye baÅlar. Yani yukarıdaki örnekte her iki komut dosyasıda eÅ zamanlı olarak indirilir. Muhtemelen small.js ilk önce indirilecektir.
Ancak komut dosyalarının sayfadaki sıraya göre çalıÅtırılması gerekir, bu nedenle long.js çalıÅtırılmasını bekler.
defer niteliÄi yalnızca dıÅarıdan aktarılan komut dosyaları içindirEÄer <script> etiketinde src yoksa defer niteliÄi yok sayılır.
async
async niteliÄi, bir scriptâin tamamiyle baÄımsız olduÄu anlamına gelir:
- Sayfa asenkron scriptâleri (async scripts) beklemez, içerik iÅlenir ve görüntülenir.
DOMContentLoadedve asenkron scriptâler (async scripts) birbirlerini beklemezler:DOMContentLoadedya bir asenkron scriptâten (async script) önce gerçekleÅebilir (bir asenkron script sayfa tamamlandıktan sonra yüklemeyi bitirirse)- â¦ya da bir asenkron scriptâten sonra (bir asenkron script küçük ya da HTTP önbelleÄinde mevcut ise)
- DiÄer scriptâler,
asyncscriptâleri için,asyncscriptâleri de onlar için beklemez.
Dolasıyla, birden fazla async scriptâimiz varsa, onlar herhangi bir sırada çalıÅtırılır. İlk önce hangisi yüklenirse o çalıÅtırılır:
<p>...script'lerden önceki içerik...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert("DOM hazır!"));
</script>
<script async src="https://javascript.info/article/script-async-defer/long.js"></script>
<script async src="https://javascript.info/article/script-async-defer/small.js"></script>
<p>...script'lerden sonraki içerik...</p>
- Sayfa içeriÄi hemen görünür:
asyncsayfayı engellemez. DOMContentLoaded,asyncâden öncede gerçekleÅebilir, sonrada gerçekleÅebilir. Burada garanti yok.- Asenkron scriptâler birbirlerini beklemezler. Küçük script
small.jsikinci sıradadır, fakat muhtemelenlong.jsâden önce yüklenecektir, dolayısıyla önce o çalıÅtırılacaktır. Buna âilk sıradakini yükleâ denir.
Asenkron scriptâler, baÄımsız bir üçüncü taraf scriptâi sayfaya eklediÄimizde harikadır: sayaçlar, reklamlar vb. bizim scriptâlerimize baÄlı olmadıkları için komut dosyalarımız onları beklememelidir.
<!-- Google Analytics genellikle bu Åekilde eklenir -->
<script async src="https://google-analytics.com/analytics.js"></script>
Dinamik Komut Dosyaları (Dynamic Scripts)
Ayrıca, JavaScript kullanarak dinamik olarak bir script ekleyebiliriz:
let script = document.createElement('script');
script.src = "/article/script-async-defer/long.js";
document.body.append(script); // (*)
Script (*), belgeye eklenir eklenmez yüklenmeye baÅlar.
Dinamik scriptler varsayılan olarak âasyncâ gibi davranırâ¦
Yani:
- Onlar herhangi bir Åeyi beklemezler, hiçbir Åeyde onları beklemez.
- İlk yüklenen script, önce çalıÅtırılır (âilk sıradakini yükleâ)
async özelliÄini false olarak ayarlarsak, yükleme sırasını belge sırası olacak Åekilde deÄiÅtirebiliriz:
let script = document.createElement('script');
script.src = "/article/script-async-defer/long.js";
script.async = false;
document.body.append(script);
ÃrneÄin, burada iki adet script ekledik. script.async=false olmadıÄından ilk sıradakini yükleye göre çalıÅtırılacaktı (muhtemelen small.js önce çalıÅacaktı). Fakat bu flag sayesinde sıra âbelgedeki sıra gibiâ olur.
function loadScript(src) {
let script = document.createElement('script');
script.src = src;
script.async = false;
document.body.append(script);
}
// long.js, async=false olduÄundan dolayı önce çalıÅtırılır.
loadScript("/article/script-async-defer/long.js");
loadScript("/article/script-async-defer/small.js");
Ãzet
async ve defer niteliklerinin ortak bir özelliÄi vardır: sayfanın yüklenmesini (render) engellemezler. Böylece kullanıcı sayfa içeriÄini okuyabilir ve sayfayla hemen etkileÅime geçebilir.
Ancak aralarında temel farklılıklar vardır:
| Sıra | DOMContentLoaded |
|
|---|---|---|
async |
İlk sırayı yükle. Belgedeki sıraları önemleri deÄildir â hangisi önce yüklenirse | Alakasız. Henüz belgenin tamamı indirilmemiÅken yüklenebilir ve çalıÅtırılabilir. Bu durum, eÄer scriptler küçük veya önbellekte mevcut ise ve belge yeterince uzun ise gerçekleÅir. |
defer |
Belge sırası (belgeye girdikleri gibi). | Belge yüklenip, çözümlendendikten sonra (gerekirse beklerler), DOMContentLoaded olayından (event) hemen önce çalıÅtırılır. |
defer kullanıyorsanız, lütfen sayfanın script yüklenmeden önce görüntüleneceÄini unutmayın.
Yani kullanıcılar sayfayı okuyabilir, fakat bazı grafiksel bileÅenler muhtemelen henüz hazır deÄildir.
Kullanıcıya neyin hazır olup, neyin olmadıÄını göstermek için uygun yerlere âyükleniyorâ ifadesi yerleÅtirilmeli, çalıÅmayan düÄmeler (button) devre dıÅı bırakılmalıdır.
Pratikte, defer tüm DOMâa ihtiyaç duyan ve/ya da göreli yürütme sırası önemli olan scriptler için kullanılır. Ve async sayaçlar, reklamlar gibi baÄımsız scriptler için kullanılır. Ve onlarda sıra önemli deÄildir.
Yorumlar
<code>kullanınız, birkaç satır eklemek için ise<pre>kullanın. EÄer 10 satırdan fazla kod ekleyecekseniz plnkr kullanabilirsiniz)