Skriptlar: async, defer
Zamonaviy saytlarda skriptlar ko'pincha HTML'dan "og'irroq" bo'ladi: ular hajmi katta, yuklanishi va ishga tushishi vaqt oladi. Brauzer HTML'ni o'qib turib <script> tegiga duch kelsa, u DOM qurishni to'xtatib skriptni yuklab bajarishi kerak. Bu esa sahifaning ko'rinishini kechiktiradi. Bu muammoni hal qilish uchun ikkita atribut bor: defer va async. Ushbu darsda ular qanday ishlashini va farqini chuqur o'rganamiz.
Bloklovchi skript muammosi
Ikkita muhim muammo bor. Birinchidan, skriptlar undan keyingi DOM elementlarini ko'ra olmaydi. Shuning uchun ularga hodisa biriktira olmaydi:
<p>...skriptdan oldingi kontent...</p>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<!-- bu tugmani skript ko'rmaydi -->
<p>...skriptdan keyingi kontent...</p>
Ikkinchidan, agar sahifaning yuqorisida katta skript bo'lsa, u "bloklovchi" โ brauzer skriptni yuklab bajarmaguncha, undan pastdagi sahifani ko'rsata olmaydi:
<p>...skriptdan oldingi kontent...</p>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<!-- bu skript yuklanmaguncha ko'rinmaydi -->
<p>...skriptdan keyingi kontent...</p>
Bunga qisman yechim bor โ skriptni sahifaning eng oxiriga, </body> yopilishidan oldin qo'yish. Unda skript o'zidan yuqoridagi barcha elementlarni ko'radi va sahifa ko'rsatilishini bloklamaydi:
<body>
...barcha kontent skriptdan yuqorida...
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
</body>
Lekin bu yechim ideal emas: brauzer skriptni faqat butun HTML hujjatni yuklab bo'lgach ko'radi va yuklashni boshlaydi. Katta HTML'larda bu sezilarli kechikish beradi. Bu muammoni defer va async atributlari hal qiladi.
defer
defer atributi brauzerga skriptni "fon rejimida" yuklashni buyuradi: brauzer skriptni yuklab olishda kutmaydi, HTML'ni qurishda davom etadi. Skript esa DOM to'liq tayyor bo'lgach bajariladi:
<p>...skriptdan oldingi kontent...</p>
<script defer src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<!-- darhol ko'rinadi, skriptni kutmaydi -->
<p>...skriptdan keyingi kontent...</p>
Boshqacha aytganda:
deferli skriptlar sahifani hech qachon bloklamaydi;deferli skriptlar har doim to'liq DOM tayyor bo'lgach, lekinDOMContentLoadedhodisasidan oldin bajariladi.
Quyidagi misol buni ko'rsatadi. Kontent darhol ko'rinadi, DOMContentLoaded esa skriptni kutadi:
<p>...skriptdan oldingi kontent...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert('DOM tayyor (skriptdan keyin)'));
</script>
<script defer src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
Bu yerda DOMContentLoaded deferli skript yuklanib bajarilishini kutadi.
defer skriptlar tartibni saqlaydi
Bir necha deferli skript bo'lsa, ular hujjatdagi tartibda bajariladi โ xuddi oddiy skriptlar kabi:
<script defer src="long.js"></script>
<script defer src="small.js"></script>
Bu yerda long.js hajmi katta bo'lsa-da, u avval yuklab bo'lingandek kutiladi va small.jsdan oldin bajariladi. Brauzer skriptlarni parallel yuklaydi (tezlik uchun), lekin ularni belgilangan tartibda ishga tushiradi.
defer โ kodning to'g'ri tartibda bajarilishi muhim bo'lganda ajoyib. Masalan, ikkinchi skript birinchisiga bog'liq bo'lsa (kutubxona + uni ishlatuvchi kod), defer tartibni kafolatlaydi.defer atributi faqat tashqi skriptlar uchun, ya'ni src ga ega skriptlar uchun ishlaydi. Agar <script>da src bo'lmasa (kodni to'g'ridan-to'g'ri yozgan bo'lsangiz), defer e'tiborga olinmaydi.async
async atributi ham skriptni fon rejimida yuklaydi, lekin butunlay boshqacha mustaqillik beradi. asyncli skript to'liq mustaqil:
- Sahifa
asyncli skriptni kutmaydi: kontent ko'rsatiladi,DOMContentLoadedhodisasi ham skriptni kutmasligi mumkin; asyncli skriptlar boshqa skriptlarni kutmaydi va ularni ham kutib turmaydi โ tartib yo'q. Qaysi biri avval yuklansa, o'sha avval bajariladi ("load-first" tartibi).
<p>...skriptdan oldingi kontent...</p>
<script>
document.addEventListener('DOMContentLoaded', () => alert('DOM tayyor!'));
</script>
<script async src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<script async src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>
Bu yerdagi tartib "belgilanmagan":
- Sahifa kontenti darhol ko'rsatiladi:
asyncbloklamaydi; DOMContentLoadedvaasyncbir-birini kutmaydi โDOMContentLoadedasyncdan oldin ham, keyin ham bo'lishi mumkin (yuklanish tezligiga qarab);asyncskriptlar bir-birini kutmaydi: qaysi biri oldin yuklansa (kichikroq yoki keshdan olingan), o'sha oldin bajariladi.
async boshqa skriptlarga bog'liq bo'lmagan mustaqil skriptlar uchun ideal: hisoblagichlar (counters), reklama, analitika kabi uchinchi tomon skriptlari. Ular sahifangizning boshqa kodiga bog'liq emas va sizning kodingiz ham ularga bog'liq emas.async va defer farqi
Ikkalasi ham skriptni bloklamasdan fon rejimida yuklaydi. Asosiy farq โ tartib va qachon bajarilishi:
- Tartib (order):
deferโ hujjatdagi tartibda bajariladi;asyncโ qaysi biri oldin yuklansa, o'sha oldin (load-first, tartib yo'q). - DOMContentLoaded:
deferโ DOM qurilib bo'lgach, lekinDOMContentLoadeddan oldin bajariladi (uni kutadi);asyncโ istalgan vaqtda,DOMContentLoadedbilan bog'liq emas. - Foydalanish:
deferโ tartib va DOM muhim bo'lganda (bog'liq skriptlar, DOM bilan ishlash);asyncโ mustaqil, boshqa hech narsaga bog'liq bo'lmagan skriptlar uchun.
Uni jadval ko'rinishida umumlashtiramiz:
Tartib DOMContentLoaded
-----------------------------------------------------------
defer | hujjatdagi tartibda | KUTADI (undan oldin)
async | load-first tartibida | BOG'LIQ EMAS (kutmaydi)
defer odatda DOM'ga muhtoj yoki bir-biriga bog'liq skriptlar uchun, async esa mustaqil skriptlar (analitika, reklama) uchun ishlatiladi. Ko'p hollarda dasturchilar bosh sahifa kodini defer bilan, uchinchi tomon vidjetlarini async bilan yuklaydi.async, ham defer yozilsa, zamonaviy brauzerlarda async ustunlik qiladi. Eski, asyncni qo'llab-quvvatlamaydigan brauzerlarda esa defer zaxira sifatida ishlaydi.Dinamik skriptlar
Skriptni HTML'da yozish shart emas โ uni JavaScript orqali dinamik ravishda ham qo'shishimiz mumkin. Buning uchun element yaratib, uni hujjatga qo'shamiz:
let script = document.createElement('script');
script.src = '/article/dynamic-scripts/long.js';
document.body.append(script); // shu paytda yuklanish va bajarilish boshlanadi
Muhim nozik jihat: dinamik qo'shilgan skriptlar sukut bo'yicha async kabi harakat qiladi. Ya'ni:
- Ular hech narsani kutmaydi va ularni ham hech kim kutmaydi;
- Avval yuklangan skript avval bajariladi (load-first tartibi).
Buni o'zgartirib, aniq tartibni tiklash mumkin โ script.async = false qo'yish orqali. Unda skriptlar oddiy defer kabi hujjatdagi tartibda bajariladi:
function loadScript(src) {
let script = document.createElement('script');
script.src = src;
script.async = false; // tartibni saqlash uchun
document.body.append(script);
}
// long.js avval bajariladi, chunki oldin qo'shildi (async=false tufayli)
loadScript('/article/dynamic-scripts/long.js');
loadScript('/article/dynamic-scripts/small.js');
Agar script.async = false qo'ymasak, tartib "load-first" bo'lardi โ kichikroq small.js ehtimol oldin yuklanib, oldin bajarilardi.
script.async = false โ bir necha dinamik skriptni to'g'ri tartibda yuklashning oddiy usuli. Bu ayniqsa modulli kutubxonalarni tartib bilan yuklashda foydali.Xulosa
async va defer ikkalasi ham skript yuklanishini bloklamasdan amalga oshiradi va foydalanuvchi sahifani deyarli darhol ko'radi. Farqlar:
defer: tartibni saqlaydi (hujjatdagi kabi),DOMContentLoadeddan oldin bajariladi, DOM tayyor bo'lishini kutadi. To'g'ri tartib va DOM muhim bo'lganda ishlating;async: mustaqil, load-first tartibi (belgilanmagan),DOMContentLoadedbilan bog'liq emas. Reklama, analitika kabi mustaqil skriptlar uchun;- Dinamik skriptlar sukut bo'yicha
asyncโ tartibni tiklash uchunscript.async = falseqo'ying.
defer yoki async ishlatganda skript yuklanmasdan turib sahifa ko'rsatilishini yodda tuting. Foydalanuvchi skript hali ishga tushmagan sahifani ko'radi โ ba'zi tugmalar hali "jonlanmagan" bo'lishi mumkin. Shu sabab yuklanish holatini ko'rsatuvchi indikator qo'shish yoki funksionallikni asta-sekin yoqish yaxshi amaliyot hisoblanadi.