Mundarija (37)
- Bu darsda
- 1. Nega bu kerak?
- 2. import() asoslari
- 2.1 Funksiyaga o'xshagan kalit so'z
- 2.2 Statik va dinamik importni taqqoslash
- 2.3 Modul obyekti
- 3. Brauzerda: bosilganda yuklash
- 3.1 Jonli misol
- 3.2 Tarmoqda nima bo'ladi
- 3.3 Yuklash xatosi
- 4. Shartga qarab yuklash
- 4.1 Manzil — o'zgaruvchidan
- 4.2 Code splitting g'oyasi
- 5. Top-level await
- 5.1 await funksiyasiz
- 5.2 Narxi: import qilganlar kutadi
- 5.3 Brauzerda
- 5.4 Qayerda ishlamaydi
- 5.5 CommonJS'dan ESM yuklash
- 6. Import attributes: JSON modul
- 6.1 with { type: "json" }
- 6.2 Nega belgi shart
- 6.3 Qayerda ishlaydi
- Hujumchi nigohi
- 7. Ko'p uchraydigan xatolar
- 7.1 .default ni unutish
- 7.2 Yo'l qayerdan hisoblanadi
- 7.3 Yuklash xatosini ushlamaslik
- 7.4 Foydalanuvchi matni manzilda
- 7.5 Kutubxonada top-level await
- 8. Mashqlar
- 1-mashq (oson): Nima chiqadi?
- 2-mashq (o'rta): Hisobot faqat kerak bo'lganda
- 3-mashq: Vazifalar qadami — eksport modulini bosilganda yuklash
- 9. Real ishda
- Xulosa
- Manbalar
JavaScript dinamik import() va top-level await: modulni kerak bo'lganda yuklash
Qisqacha: Dinamik
import("./modul.js")— modulni kod ishlayotgan paytda, kerak bo'lganda yuklaydi va modul obyekti bilan bajariladigan Promise qaytaradi:const { eksportMatni } = await import("./paket.js"). Sahifa ochilishi tezlashadi: kam ishlatiladigan kod faqat kerak bo'lganda keladi. Top-levelawait— modulning eng yuqori qatorida, funksiyasizawaityozish; qulay, lekin shu modulni import qilganlarning hammasini kuttiradi. JSON fayl esawith { type: "json" }belgisi bilan import qilinadi.
Bu darsda
import()ni yoza olasiz va u statikimportdan nimasi bilan farq qilishini tushuntira olasiz.- Modul obyektidan nomli va default eksportlarni ola olasiz (
.defaulttuzog'i bilan). - Modulni tugma bosilganda yoki shartga qarab yuklay olasiz va yuklash xatosini to'g'ri ushlaysiz.
- Top-level
awaitqayerda ishlashini va uning narxini bilasiz. - JSON faylni import attributes bilan import qila olasiz.
vazifalarilovasidapaket.jsni faqat «JSON qilib chiqarish» bosilganda yuklaysiz.
Oldin bilishingiz kerak: ESM import, Brauzerda ESM va import maps, CommonJS va ESM bilan o'zaro ishlash, async / await, Ushlanmagan xatolar.
1. Nega bu kerak?
ESM import darsida importlar faylning boshida yozilishini va kod ishga tushishidan oldin ulanishini ko'rgan edik. Bu ishonchli: brauzer sahifa ochilishi bilan butun modul grafigini biladi va hammasini yuklaydi.
Lekin "hammasini" — ba'zan ortiqcha. vazifalar ilovasini eslang: oltita modul, ulardan biri — paket.js (eksport va import). Foydalanuvchilarning ko'pi vazifa qo'shadi, belgilaydi, o'chiradi — «JSON qilib chiqarish» tugmasini esa kamdan-kam bosadi. Baribir paket.js har safar, sahifa ochilishi bilan yuklanadi.
Kichik ilovada bu sezilmaydi. Katta ilovada esa farq katta. «Bahor» saytida chekni PDF qilib chiqaradigan kutubxona yuzlab kilobayt bo'lishi mumkin. Uni menyuni ochgan har mehmon yuklasa, sahifa sekin ochiladi. Aslida uni faqat «Chekni yuklab olish» ni bosgan bir necha kishi ishlatadi.
Shuning uchun ESM import darsida va'da bergan edik: modulni shartga qarab yoki kerak bo'lganda yuklash uchun boshqa vosita bor. U Promise qaytaradi — endi Promise'ni bilasiz, navbat keldi.
2. import() asoslari
2.1 Funksiyaga o'xshagan kalit so'z
Dinamik import — import(manzil). U modulni yuklaydi, bajaradi va modul obyekti bilan bajariladigan Promise qaytaradi:
const util = await import("node:util");
console.log(util.format("%s — %d so'm", "Osh", 35000));
const vada = import("node:util");
console.log(vada instanceof Promise);Konsolda:
Osh — 35000 so'm
trueQatorma-qator:
await import("node:util")— Node'ning tayyorutilmodulini yuklaydi.util.formatmatnga qiymat qo'yadi:%so'rniga satr,%do'rniga son.import(...)ning o'zi — Promise. Ikkinchi qism buniinstanceofbilan ko'rsatdi.
Bu yerda await funksiyadan tashqarida yozilgan — buni top-level await deyishadi. U faqat modullarda ishlaydi va uni shu darsning «Top-level await» bo'limida ochamiz. Blok ostida «Ishga tushir» yo'q, chunki node:util faqat Node'da bor. Bunday bloklarni va bir nechta fayldan iborat misollarni kompyuteringizda, .mjs faylda sinang.
import(...) funksiyaga o'xshaydi, lekin funksiya emas — maxsus sintaksis. Uni o'zgaruvchiga yozib yoki import.call(...) qilib bo'lmaydi.
2.2 Statik va dinamik importni taqqoslash
Statik import ... from |
Dinamik import() |
|
|---|---|---|
| Qayerda | faylning eng yuqori darajasida | istalgan joyda: funksiya, if, tinglovchi |
| Qachon yuklanadi | kod ishga tushishidan oldin | shu qator bajarilganda |
| Manzil | faqat tayyor satr | istalgan ifoda: `./tillar/${til}.mjs` |
| Natija | nomlar faylga ulanadi | Promise → modul obyekti |
| Oddiy skript va CommonJS'da | yo'q | bor |
Oxirgi qator — muhim. Statik import faqat ESM modulda ishlaydi. import() esa oddiy <script> da ham, CommonJS (.cjs) faylda ham ishlaydi. CommonJS va ESM darsida aytilgan "import() ishlating" maslahati shundan.
2.3 Modul obyekti
import() qaytaradigan obyekt — modul nomlar maydoni (module namespace object). Unda modulning har nomli eksporti — xususiyat, default eksporti esa default nomli xususiyat. ESM import darsidagi menyu.mjs ni dinamik yuklaymiz:
// menyu.mjs
console.log("menyu.mjs bajarildi");
export const narxlar = { osh: 35000, manti: 30000 };
export function narxniTop(taom) {
return narxlar[taom] ?? 0;
}
export default function menyuniChiqar() {
console.log("Osh, Manti");
}// asosiy.mjs
console.log("asosiy.mjs boshlandi");
const menyu = await import("./menyu.mjs");
console.log(Object.keys(menyu));
menyu.default();
console.log(menyu.narxniTop("osh"));
const { default: chiqar, narxniTop } = await import("./menyu.mjs");
console.log(chiqar === menyu.default, narxniTop("manti"));node asosiy.mjs bilan ishga tushirdik:
asosiy.mjs boshlandi
menyu.mjs bajarildi
[ 'default', 'narxlar', 'narxniTop' ]
Osh, Manti
35000
true 30000To'rt narsaga qarang:
- Tartib.
asosiy.mjs boshlandibirinchi chiqdi. Statik importda esamenyu.mjsdoim birinchi bajarilardi — importlar kod ishga tushishidan oldin ulanadi (Modul semantikasi). Dinamik import — shu qatorga yetib kelgandagina. default— oddiy xususiyat. Default eksportni chaqirish:menyu.default().- Destructuring.
const { default: chiqar, narxniTop } = ...— kerakli nomlarni darhol olish.default— zaxiralangan so'z, uni o'zgaruvchi nomi qilib bo'lmaydi, shuning uchundefault: chiqarbilan qayta nomlaymiz (Obyekt destructuring). - Bir marta bajariladi. Ikkinchi
import("./menyu.mjs")damenyu.mjs bajarildiqayta chiqmadi. Modul keshda: harimport()o'sha bitta modul obyektini qaytaradi.
Modul obyektini o'zgartirib bo'lmaydi — undagi nomlar faqat o'qish uchun:
const menyu = await import("./menyu.mjs");
menyu.narxlar = {};TypeError: Cannot assign to read only property 'narxlar' of object '[object Module]'"Modul obyektining faqat o'qiladigan narxlar xususiyatiga qiymat berib bo'lmaydi". Bu — Modul semantikasi darsidagi "import — faqat o'qish uchun" qoidasining o'zi. Bu xato faqat qat'iy rejimda chiqadi — modullar esa doim qat'iy rejimda ishlaydi.
Tekshirib ko'ring:
const m = await import("./menyu.mjs"); m();nima beradi?
Javob
TypeError: m is not a function. m — funksiya emas, modul obyekti. Default funksiya uning ichida: m.default(). Bu import() dagi eng ko'p uchraydigan xato — statik import menyuniChiqar from da default to'g'ridan-to'g'ri kelardi, dinamikda esa .default orqali.
3. Brauzerda: bosilganda yuklash
3.1 Jonli misol
«Bahor» saytida buyurtma qabul qilinganda ekranda konfetti "otilsin". Konfetti kutubxonasi faqat shu lahzada kerak — sahifa ochilganda uni yuklash shart emas. CDN'dagi canvas-confetti (1.9.4 versiyasi) kutubxonasini tugma bosilganda yuklaymiz:
<style>
body { font: 1rem/1.5 system-ui, sans-serif; margin: 1rem; }
button { font: inherit; padding: 0.4rem 0.8rem; }
canvas { display: block; width: 100%; height: 160px; }
</style>
<button id="buyurtma" type="button">Buyurtma berish</button>
<p id="holat" role="status"></p>
<canvas id="bayram"></canvas>
<script type="module">
const KONFETTI =
"https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.4/+esm";
const tugma = document.getElementById("buyurtma");
const holat = document.getElementById("holat");
tugma.addEventListener("click", async () => {
holat.textContent = "Buyurtma qabul qilindi!";
const modul = await import(KONFETTI);
console.log("Modul keldi:", Object.keys(modul));
const otish = modul.default.create(
document.getElementById("bayram"),
{ resize: true, useWorker: false },
);
otish({ particleCount: 80, disableForReducedMotion: true });
});
console.log("Sahifa tayyor: konfetti hali yuklanmagan");
</script>Konsolda:
Sahifa tayyor: konfetti hali yuklanmaganEndi «Buyurtma berish» ni bosing. Konsolga yangi qator qo'shiladi va konfetti otiladi (tizimingizda "harakatni kamaytirish" yoqilgan bo'lsa — otilmaydi: disableForReducedMotion). Birinchi bosishdan keyin konsolda:
Sahifa tayyor: konfetti hali yuklanmagan
Modul keldi: (2) ['create', 'default']Ikkinchi bosishda kutubxona qayta yuklanmaydi — modul keshda, import() darhol tayyor obyektni beradi. Konsoldagi (2) ['create', 'default'] — Chrome'ning massiv ko'rinishi: ikki element, kutubxonaning ikki eksporti. Node buni [ 'create', 'default' ] deb yozardi — ma'nosi bir xil. useWorker: false — kutubxona odatda alohida oqim (Web Worker) ochadi, saytdagi natija oynasi esa xavfsizlik uchun bunga ruxsat bermaydi. O'z sahifangizda bu sozlama shart emas.
+esm — jsDelivr CDN'ning xizmati: npm paketini brauzer to'g'ridan-to'g'ri import qila oladigan ES modulga aylantirib beradi. Paket va CDN'lar haqida — npm'ga birinchi qadam va 16-qismda.
3.2 Tarmoqda nima bo'ladi
Vaqt bo'yicha: sahifa ochilganda — faqat sahifaning o'z kodi. Bosilganda — kutubxona.
sequenceDiagram
participant B as Brauzer
participant S as Server / CDN
B->>S: index.html, asosiy.js
S-->>B: sahifa tayyor
Note over B: Foydalanuvchi o'qiydi...
B->>B: «Buyurtma berish» bosildi
B->>S: import("…canvas-confetti…")
S-->>B: modul
Note over B: Ikkinchi bosish — keshdan, so'rovsizDevTools'ning Network panelida buni o'z ko'zingiz bilan ko'rasiz: sahifa ochilganda ro'yxatda konfetti fayli yo'q, bosgandan keyin paydo bo'ladi (DevTools Network).
3.3 Yuklash xatosi
Tarmoq uzilsa yoki fayl topilmasa, import() Promise'i rad etiladi. Chrome'dagi xabar:
TypeError: Failed to fetch dynamically imported module: https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.4/yoq.mjs"Dinamik import qilinayotgan modulni olib bo'lmadi". Sababini (404 yoki internet yo'q) xabar aytmaydi — u Network panelida yoki konsoldagi oldingi Failed to load resource qatorida. Bu xato ham oddiy rad etilish: uni try/catch va await bilan ushlaysiz. Ushlamasangiz — konsolda Uncaught (in promise) TypeError: ... (Ushlanmagan xatolar).
Bitta nozik joy bor — uni Chrome 154 da sinab ko'rdik. Agar modul bir marta yuklanmasa, keyingi import() uni qayta so'ramaydi: brauzer muvaffaqiyatsizlikni ham eslab qoladi va darhol o'sha xatoni qaytaradi. Internet qaytgandan keyin ham tugmani qayta bosish yordam bermaydi — faqat sahifani yangilash. Shuning uchun foydalanuvchiga "qayta bosing" emas, "sahifani yangilang" deb yozing.
Tekshirib ko'ring: Konfetti misolida
import()ni tinglovchi ichidan olib, faylning boshiga statikimport confetti from "https://..."qilib qo'ysak, nima o'zgaradi?
Javob
Kutubxona sahifa ochilishi bilan, hech kim bosmasa ham yuklanadi. Ishlash bir xil, lekin har mehmon ortiqcha faylni yuklaydi. Yana bir farq: CDN ishlamay qolsa, statik importda butun modul ishlamaydi — tugma ham, sahifaning qolgan kodi ham. Dinamik importda faqat konfetti bo'lmaydi.
4. Shartga qarab yuklash
4.1 Manzil — o'zgaruvchidan
ESM import darsida import { matnlar } from "./" + til + ".mjs" xato bergan edi: statik importda manzil faqat tayyor satr. import() da esa istalgan ifoda bo'ladi. «Bahor» sayti ikki tilda: o'zbekcha va inglizcha. Har til matnlari alohida faylda, faqat tanlangan til yuklanadi:
// tillar/uz.mjs
export const salom = "Xush kelibsiz!";
export const menyu = "Menyu";// tillar/en.mjs
export const salom = "Welcome!";
export const menyu = "Menu";// til.mjs — tanlangan tildagi matnlarni yuklaydi
const TILLAR = ["uz", "en"];
const til = process.argv[2] ?? "uz";
if (!TILLAR.includes(til)) {
console.log(`«${til}» tili yo'q, o'zbekcha ochamiz`);
}
const tanlangan = TILLAR.includes(til) ? til : "uz";
const matnlar = await import(`./tillar/${tanlangan}.mjs`);
console.log(matnlar.salom, "|", matnlar.menyu);Terminalda uch marta ishga tushirdik — process.argv[2] — buyruqdagi birinchi qo'shimcha so'z (process obyekti):
$ node til.mjs
Xush kelibsiz! | Menyu
$ node til.mjs en
Welcome! | Menu
$ node til.mjs fr
«fr» tili yo'q, o'zbekcha ochamiz
Xush kelibsiz! | MenyuTILLAR ro'yxati — oq ro'yxat (JSON chuqur darsidagi g'oya): import qilinadigan fayl faqat ma'lum to'plamdan. Ro'yxatsiz fr uchun Node xato berardi:
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '…/tillar/fr.mjs' imported from …/til.mjs"til.mjs dan import qilingan tillar/fr.mjs modulini topib bo'lmadi". Oq ro'yxatning yana bir, muhimroq sababi bor — keyingi bo'limda.
4.2 Code splitting g'oyasi
Haqiqiy loyihalarda kodni bundler (ko'p faylni brauzer uchun yig'adigan vosita, masalan Vite — 16-qismda) yig'adi. U import() ni ko'rganda o'sha modulni alohida faylga — bo'lak (chunk) ga — ajratadi. Asosiy fayl kichrayadi, bo'lak esa faqat import() bajarilganda yuklanadi. Buni code splitting (kodni bo'lish) deyishadi. Sahifalar bo'yicha bo'lish (har sahifa — alohida bo'lak) va og'ir komponentlarni kechiktirish (React'da lazy) — hammasi import() ustiga qurilgan. Chuqur — Code splitting va lazy darslarida; hozir bilish shart emas.
5. Top-level await
5.1 await funksiyasiz
Shu paytgacha await ni faqat async funksiya ichida yozdik. ES modullarda esa uni faylning eng yuqori darajasida ham yozish mumkin — bu top-level await (yuqori darajadagi await):
function serverdanOl() {
return new Promise((resolve) => {
setTimeout(resolve, 200, { ochilish: 7, yopilish: 23 });
});
}
console.log("Sozlamalar so'raldi");
const { ochilish, yopilish } = await serverdanOl();
console.log(`Ish vaqti: ${ochilish}:00–${yopilish}:00`);Konsolda:
Sozlamalar so'raldi
Ish vaqti: 7:00–23:00async function boshla() { ... } boshla(); o'rami kerak bo'lmadi. Kirish faylida (ilova boshlanadigan joyda) bir martalik sozlash uchun bu juda qulay.
5.2 Narxi: import qilganlar kutadi
Top-level await li modul tugamaguncha, uni import qilgan modullar bajarilmaydi. Uch faylda ko'ramiz:
// sozlamalar.mjs — "serverdan" ish vaqtini oladi
function serverdanOl() {
return new Promise((resolve) => {
setTimeout(resolve, 500, { ochilish: 7, yopilish: 23 });
});
}
console.log("sozlamalar: so'rov yuborildi");
export const ishVaqti = await serverdanOl();
console.log("sozlamalar: javob keldi");// menyu.mjs
console.log("menyu: bajarildi");
export const taomlar = ["osh", "lag'mon", "manti"];// asosiy.mjs
import { ishVaqti } from "./sozlamalar.mjs";
import { taomlar } from "./menyu.mjs";
console.log("asosiy: boshlandi");
const { ochilish, yopilish } = ishVaqti;
console.log(`${ochilish}:00–${yopilish}:00`, taomlar);node asosiy.mjs:
sozlamalar: so'rov yuborildi
menyu: bajarildi
sozlamalar: javob keldi
asosiy: boshlandi
7:00–23:00 [ 'osh', "lag'mon", 'manti' ]Kim kimni import qiladi — sxemada. Strelka "import qiladi" degani:
flowchart TD
A["asosiy.mjs<br/>(kutadi)"] --> S["sozlamalar.mjs<br/>await 500 ms"]
A --> M["menyu.mjs<br/>(darhol bajariladi)"]Kuzating:
sozlamalar.mjsbirinchi bajarildi vaawaitda to'xtadi.menyu.mjskutmadi — usozlamalarga bog'liq emas, shuning uchun shu orada bajarildi.asosiy.mjsesa ikkalasini import qiladi. U 500 ms kutdi —sozlamalartugaguncha uning birorta qatori ham ishlamadi.
Endi tasavvur qiling: sozlamalar.mjs ni loyihadagi 20 ta modul import qiladi, server esa sekin — 3 soniya. Butun ilova 3 soniya "o'lik" turadi. Yoki server javob bermaydi — ilova umuman ochilmaydi. Bu top-level await ning narxi.
Qoidalar:
- Kirish faylida — mayli.
asosiy.jsda bir martalik sozlash, til faylini yuklash. - Ko'p import qilinadigan modulda — ehtiyot bo'ling. Ayniqsa tarmoq so'rovi bilan: unga Asinxron naqshlar dagi timeout qo'ying yoki so'rovni funksiyaga o'rab, kerakli joyda chaqiring.
- Kutubxonada — yo'q. Kutubxonangizni ishlatgan har loyiha kutadi, CommonJS'dan esa
requireqilib bo'lmaydi.
5.3 Brauzerda
<script type="module"> ham modul — unda top-level await ishlaydi. Ikki modul skripti bor sahifa. Birinchisi kutubxonaning package.json faylini JSON sifatida yuklaydi (with { type: "json" } — keyingi bo'limda):
<p>Konsolni kuzating.</p>
<script type="module">
console.log("1-modul: boshlandi");
const MANZIL =
"https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.4/package.json";
const paket = await import(MANZIL, { with: { type: "json" } });
console.log("1-modul:", paket.default.name, paket.default.version);
</script>
<script type="module">
console.log("2-modul: ishladi");
</script>Konsolda:
1-modul: boshlandi
2-modul: ishladi
1-modul: canvas-confetti 1.9.4Birinchi modul tarmoqni kutayotganda ikkinchisi ishladi: top-level await faqat shu modulni import qilganlarni kuttiradi, sahifadagi boshqa skriptlarni emas.
5.4 Qayerda ishlamaydi
Oddiy skriptda (<script> — type="module" siz) va CommonJS faylda top-level await — sintaksis xatosi. Node'da .cjs fayl:
SyntaxError: await is only valid in async functions and the top level bodies of modules"await faqat async funksiyalarda va modullarning yuqori darajasida yaroqli". Xabarning o'zi qoidani aytib turibdi. Tuzatish — faylni modulga aylantirish (.mjs, "type": "module" yoki type="module") yoki async funksiya ichiga olish.
Maslahat: Saytimizdagi «Ishga tushir» tugmasi kodni odatda oddiy skript sifatida bajaradi. Blokda top-level
awaityokiimportbo'lsa esa —<script type="module">dagidek, modul sifatida. Shuning uchun «awaitfunksiyasiz» bo'limidagi blok saytda ham ishlaydi. Oldingi darslardaawaitniasyncfunksiya ichida yozganimizning sababi — o'sha paytda top-levelawaithali o'tilmagan edi.
Tekshirib ko'ring:
asosiy.mjsfaqatmenyu.mjsni import qiladi.menyu.mjsesasozlamalar.mjsni (unda 500 ms top-levelawait).asosiy.mjskutadimi?
Javob
Ha. Kutish zanjir bo'ylab yuqoriga tarqaladi: sozlamalar tugamaguncha menyu bajarilmaydi, menyu tugamaguncha — asosiy. Grafikning istalgan joyidagi top-level await uni import qilgan hamma "ota" modullarni kuttiradi.
5.5 CommonJS'dan ESM yuklash
CommonJS va ESM darsida top-level await li ESM'ni require qilib bo'lmasligini ko'rgan edik (ERR_REQUIRE_ASYNC_MODULE). Endi sababini bilasiz: bunday modul darhol tayyor bo'lmaydi, require esa kutishni bilmaydi. Yechim — import(). U .cjs faylda ham ishlaydi, faqat top-level await yo'q — shuning uchun async funksiya ichida:
// hisobot.cjs — CommonJS fayl
async function boshla() {
const { ishVaqti } = await import("./sozlamalar.mjs");
console.log("hisobot:", ishVaqti.yopilish);
}
boshla();
console.log("hisobot: boshla() chaqirildi");sozlamalar.mjs — «Narxi: import qilganlar kutadi» bo'limidagi fayl (500 ms li top-level await bilan). Natija:
hisobot: boshla() chaqirildi
sozlamalar: so'rov yuborildi
sozlamalar: javob keldi
hisobot: 23boshla() birinchi await da to'xtab, boshqaruvni qaytardi — shuning uchun "chaqirildi" birinchi chiqdi.
6. Import attributes: JSON modul
6.1 with { type: "json" }
Menyu narxlari alohida narxlar.json faylida. Uni to'g'ridan-to'g'ri import qilish mumkin — faqat brauzer va Node'ga bu JSON ekanini aytish kerak:
{ "osh": 35000, "lagmon": 28000, "manti": 30000, "choy": 5000 }// narx.mjs
import narxlar from "./narxlar.json" with { type: "json" };
console.log(narxlar.osh);
const m = await import("./narxlar.json", { with: { type: "json" } });
console.log(m.default === narxlar, Object.keys(m));node narx.mjs:
35000
true [ 'default' ]with { type: "json" }— import attributes (import belgilari): modulga qo'shimcha ma'lumot. Statik importda — manzildan keyin, dinamikda — ikkinchi argumentdagiwithxususiyati.- JSON moduldan faqat
defaulteksport keladi — butun obyekt. Nomli import (import { osh } from ...) bo'lmaydi. - Modul keshi bu yerda ham ishlaydi: ikkala import bitta obyektni berdi.
6.2 Nega belgi shart
Belgisiz yozib ko'ramiz — import narxlar from "./narxlar.json";. Node 24:
TypeError [ERR_IMPORT_ATTRIBUTE_MISSING]: Module "file:///…/narxlar.json" needs an import attribute of "type: json""Modulga type: json import belgisi kerak". Chrome esa konsolga yozadi:
Failed to load module script: Expected a JavaScript-or-Wasm module script but the server responded with a MIME type of "application/json". Strict MIME type checking is enforced for module scripts per HTML spec."Modul skriptini yuklab bo'lmadi: JavaScript modul kutilgan edi, server esa application/json turini qaytardi". Nega bunchalik qattiq? Xavfsizlik uchun. Brauzer faylning turini serverning javobidan biladi. Agar .json faylni JavaScript sifatida qabul qilsa, buzilgan yoki begona server JSON o'rniga kod yuborib, uni sizning sahifangizda bajarishi mumkin edi. type: "json" — "men faqat ma'lumot kutyapman, kod bo'lsa — rad et" degan kafolat.
Eski maqolalarda assert { type: "json" } ni uchratasiz — bu taklifning birinchi varianti. U olib tashlangan: Node 24 da SyntaxError: Unexpected identifier 'assert'. Yangi kodda faqat with.
6.3 Qayerda ishlaydi
- JSON modullar — Chrome va Edge 123, Firefox 138, Safari 17.2. 2025 yil aprelidan Baseline (hamma asosiy brauzerlarda). Node'da — barqaror, ogohlantirishsiz (Node 24 da tekshirildi).
- CSS modullar —
import jadval from "./menyu.css" with { type: "css" }. Natija — tayyorCSSStyleSheetobyekti, u sahifagadocument.adoptedStyleSheetsorqali ulanadi. Chrome va Edge 123, Firefox 147 da bor, Safari'da hali yo'q — Baseline emas (web-features 3.40). Asosan Web Components bilan ishlatiladi (Web Components). ESMimportdarsida va'da qilganwith { type: "css" }— shu.
Vite kabi bundlerlar JSON va CSS importlarini belgisiz ham qabul qiladi — ular faylni yig'ish paytida o'zlari aylantiradi. Bundlersiz, brauzerda yoki Node'da esa belgi majburiy.
Hujumchi nigohi
import() ning manzili o'zgaruvchidan kelsa, "bu o'zgaruvchini kim boshqaradi?" degan savol tug'iladi.
Hujum. Sardor tilni URL'dagi ?til= qiymatidan olishni yozdi: import(`./tillar/${new URLSearchParams(location.search).get("til")}.js`). URLSearchParams URL parametrlarini o'qiydi — uni URL va URLSearchParams darsida o'rganamiz. Hujumchi foydalanuvchiga havola yuboradi: ?til=../../yuklamalar/boshqa. Agar saytda foydalanuvchilar fayl yuklay olsa, brauzer hujumchining faylini kod sifatida bajaradi — sizning sahifangiz nomidan, mehmonning tizimga kirgan holatida. Node serverda esa so'rovdan kelgan nom bilan import() — serverdagi istalgan .mjs faylni ishga tushirish imkoniyati.
Himoya. Bugungi kod bunga qarshi turadi: manzil hech qachon foydalanuvchi matnidan to'g'ridan-to'g'ri yig'ilmaydi. Faqat oq ro'yxatdagi qiymat (TILLAR.includes(til)) ishlatiladi, ro'yxatda yo'q bo'lsa — standart til. import() — kod bajarish; unga beriladigan manzil eval ga beriladigan matn kabi ehtiyot bo'lishni talab qiladi.
7. Ko'p uchraydigan xatolar
7.1 .default ni unutish
const chiqar = await import("./menyu.mjs"); chiqar(); → TypeError: chiqar is not a function. Tuzatish: (await import(...)).default yoki const { default: chiqar } = await import(...).
7.2 Yo'l qayerdan hisoblanadi
import("./paket.js") dagi ./ — sahifaga emas, shu qator yozilgan modul fayliga nisbatan. assets/js/asosiy.js ichida ./paket.js — assets/js/paket.js. index.html ga nisbatan yozib (./assets/js/paket.js) qo'ysangiz — assets/js/assets/js/paket.js qidiriladi va 404.
7.3 Yuklash xatosini ushlamaslik
Tarmoq uzilganda await import() rad etiladi. Ushlanmasa — tugma "jim" buziladi. Tuzatish: try/catch, foydalanuvchiga "sahifani yangilang" xabari (Chrome muvaffaqiyatsiz importni qayta so'ramaydi).
7.4 Foydalanuvchi matni manzilda
import(`./${nom}.js`), nom esa URL yoki formadan — begona kodni bajarish yo'li. Tuzatish: oq ro'yxat.
7.5 Kutubxonada top-level await
Sizning modulingizni import qilgan har kod kutadi va CommonJS'dan require qilolmaydi. Tuzatish: asinxron ishni eksport qilinadigan funksiyaga o'rang — chaqiruvchi o'zi qachon kutishni hal qilsin.
8. Mashqlar
1-mashq (oson): Nima chiqadi?
taom.mjs fayli:
export const nom = "Manti";
export default 30000;Boshqa modulda:
const m = await import("./taom.mjs");
console.log(m.nom);
console.log(m.default);
console.log(Object.keys(m).length);
const { default: narx } = await import("./taom.mjs");
console.log(narx === m.default);Yechim
Manti
30000
2
trueModul obyektida ikki xususiyat: default va nom. Default eksport — son, u default xususiyatida. Ikkinchi import() o'sha keshlangan modulni qaytaradi, shuning uchun narx va m.default — bir xil qiymat.
2-mashq (o'rta): Hisobot faqat kerak bo'lganda
kassa.mjs dasturi kunlik savdoni chiqaradi. Hisobotni Excel'ga mos CSV matniga aylantiradigan kod og'ir va kam ishlatiladi — u csv.mjs da. Shunday yozing:
csv.mjs—export function csvYasa(qatorlar): har qatorninom,narxko'rinishiga keltirib,\nbilan birlashtiradi (sarlavha qatori —taom,narx). Fayl boshidaconsole.log("csv.mjs yuklandi").kassa.mjs— savdo massivini konsolga chiqaradi. Agar buyruqda--csvbo'lsa (process.argv.includes("--csv")),csv.mjsni dinamik import qilib, CSV matnini ham chiqaradi.
node kassa.mjs da "csv.mjs yuklandi" chiqmasligi, node kassa.mjs --csv da esa chiqishi kerak. Savdo: osh 35 000, manti 30 000. Fayllarni kurs/mashqlar/11/16-dinamik-import/ ga saqlang. Ishora: massivni satrga aylantirish — map va join (Callback imzosi va HOF metodlari).
Yechim
// csv.mjs
console.log("csv.mjs yuklandi");
export function csvYasa(qatorlar) {
const satrlar = qatorlar.map((q) => `${q.nom},${q.narx}`);
return ["taom,narx", ...satrlar].join("\n");
}// kassa.mjs
const savdo = [
{ nom: "osh", narx: 35000 },
{ nom: "manti", narx: 30000 },
];
console.log(`Bugun: ${savdo.length} ta taom sotildi`);
if (process.argv.includes("--csv")) {
const { csvYasa } = await import("./csv.mjs");
console.log(csvYasa(savdo));
}$ node kassa.mjs
Bugun: 2 ta taom sotildi
$ node kassa.mjs --csv
Bugun: 2 ta taom sotildi
csv.mjs yuklandi
taom,narx
osh,35000
manti,30000Birinchi buyruqda csv.mjs umuman o'qilmadi. Statik import { csvYasa } from "./csv.mjs" bo'lsa, u har safar yuklanardi va "csv.mjs yuklandi" ikkala holatda chiqardi.
git add 11/16-dinamik-import/
git commit -m "11/16: CSV hisobotni faqat --csv bilan yukla"3-mashq: Vazifalar qadami — eksport modulini bosilganda yuklash
vazifalar v2 da asosiy.js paket.js ni statik import qiladi, index.html esa uni modulepreload bilan oldindan yuklaydi (Brauzerda ESM va import maps). Natijada eksport kodi har sahifa ochilganda keladi. Endi:
- Yangi branch:
git switch -c feature/dinamik-import. asosiy.jsdanpaket.jsning statik importini olib tashlang.- «JSON qilib chiqarish» (
#eksport-tugma) bosilgandapaket.jsniawait import("./paket.js")bilan yuklang vaeksportMatnini modul obyektidan oling. «Import qilish» tugmasi hampaketniOqini ishlatadi — unga ham shu yo'l. - Yuklash muvaffaqiyatsiz bo'lsa —
elonQilbilan tushunarli xabar, ro'yxat o'zgarmasin. index.htmldagipaket.jsningmodulepreloadqatorini olib tashlang — aks holda brauzer uni baribir oldindan yuklaydi.README.mdni yangilang.
Ishora: ikkala tinglovchiga bitta yordamchi yozing — paketniYukla() modul obyektini yoki xatoda null qaytarsin. Tinglovchilar async bo'ladi.
Yechim
asosiy.js boshidagi importlardan import { eksportMatni, paketniOqi } from "./paket.js"; qatori o'chiriladi. VazifaXatosi importi (vazifa.js dan) qoladi — vazifa.js ilova ochilishida baribir kerak. Yordamchi — tinglovchilardan oldin:
// paket.js — faqat eksport yoki import bosilganda yuklanadi
async function paketniYukla() {
try {
return await import("./paket.js");
} catch (xato) {
elonQil("Eksport moduli yuklanmadi. Sahifani yangilang.");
console.error(xato);
return null;
}
}Ikki tinglovchi:
eksportTugma.addEventListener("click", async () => {
const paket = await paketniYukla();
if (paket === null) {
return;
}
eksportMatn.value = paket.eksportMatni(holat.vazifalar);
eksportMatn.focus();
eksportMatn.select();
elonQil("JSON tayyor. Nusxa olish uchun Ctrl+C bosing.");
});
importTugma.addEventListener("click", async () => {
importXatosiniTozala();
elonQil("");
const paket = await paketniYukla();
if (paket === null) {
return;
}
try {
const malumotlar = paket.paketniOqi(importMatn.value);
royxatniAlmashtir(malumotlar);
elonQil(`${malumotlar.length} ta vazifa import qilindi.`);
} catch (xato) {
if (xato instanceof VazifaXatosi) {
importXatosiniKorsat(xato.message);
return;
}
importXatosiniKorsat("Kutilmagan xato: import bajarilmadi.");
throw xato;
}
});Nimalar o'zgardi:
- Tinglovchilar
async.await paketniYukla()birinchi bosishda faylni yuklaydi, keyingilarida keshdan darhol oladi. - Yuklash xatosi
paketniYuklaichida ushlanadi:#elonda xabar, konsolda texnik tafsilot (console.error). Tinglovchinullni ko'rib, hech narsaga tegmay chiqadi. - Importdagi
try/catcho'zgarmadi — u endi faqatpaketniOqixatolarini ushlaydi. Modul yuklanmasa, import matni joyida qoladi va ro'yxat almashtirilmaydi. elonQil— Taymerlar darsidagi versiya: xabar 3 soniyada o'zi yo'qoladi.
index.html dan bitta qator o'chiriladi:
<link rel="modulepreload" href="assets/js/paket.js">README.md dagi modullar ro'yxatida:
- `paket.js` — eksport va import: `{ versiya: 1, vazifalar }`.
Statik import qilinmaydi: `asosiy.js` uni tugma bosilganda
`import()` bilan yuklaydi, `modulepreload` ro'yxatida yo'q.Live Server bilan sinang (DevTools → Network, "JS" filtri):
- Sahifani yangilang — ro'yxatda
paket.jsyo'q. Vazifa qo'shish, belgilash, filtr — hammasi avvalgidek. - «JSON qilib chiqarish» —
paket.jspaydo bo'ladi, maydonda JSON, e'lon chiqadi. Yana bosing — yangi so'rov yo'q. - Eksport matnini «Import qilish» maydoniga qo'yib, import qiling — ro'yxat almashtiriladi. Buzuq matn — avvalgidek xato xabari.
- Yuklash xatosi: sahifani yangilang, Network panelidagi "No throttling" ro'yxatidan Offline ni tanlang va «JSON qilib chiqarish» ni bosing — e'londa "Eksport moduli yuklanmadi. Sahifani yangilang.", ro'yxat joyida. Online'ga qaytaring va yana bosing — xabar takrorlanadi (brauzer muvaffaqiyatsiz importni eslab qolgan). Sahifani yangilang — eksport ishlaydi.
Bu qadamlarni biz Chrome 154 da avtomatik sinadik: paket.js faqat birinchi bosishda so'raldi, oflayn holatdan keyin esa faqat sahifani yangilash yordam berdi.
Maslahat: Bu qaror abadiy emas. Qism davomida
vazifalarga saqlash moduli qo'shiladi vapaket.jssahifa ochilishida ham kerak bo'lib qoladi. Shunda yakuniy loyihada o'lchab ko'rib, statik importga qaytamiz. Texnikaning o'zi — kam ishlatiladigan kodni kechiktirish — to'g'riligicha qoladi.
git add assets/js/asosiy.js index.html README.md
git commit -m "Eksport: paket.js ni bosilganda import() bilan yukla"
git switch main
git merge feature/dinamik-import
git branch -d feature/dinamik-import
git push9. Real ishda
- Sahifalar bo'yicha bo'lish. React, Vue, Next.js ilovalarida har sahifa — alohida bo'lak: "Profil" sahifasining kodi faqat unga o'tganda yuklanadi. Ichida —
import(). - Og'ir kutubxonalar. PDF yasash, grafik chizish, matn muharriri, xarita — tugma bosilganda yoki element ko'ringanda yuklanadi. Katta ilovalarning veb-versiyalari shu bilan tez ochiladi.
- Tillar va mintaqalar. Tarjima fayllari tanlangan til bo'yicha dinamik yuklanadi — bugungi
tillar/misoli. - Node. CLI dasturlar kam ishlatiladigan buyruqlarning kodini faqat kerak bo'lganda import qiladi — dastur tezroq ishga tushadi. Konfiguratsiya fayllari (
vite.config.js,eslint.config.js) ham ichkaridaimport()bilan o'qiladi. - Intervyu. "Code splitting nima va qanday qilinadi?", "
import()vaimportfarqi?", "Top-levelawaitning kamchiligi?"
Xulosa
import(manzil)— modulni ish paytida yuklaydi va modul obyekti bilan bajariladigan Promise qaytaradi; oddiy skript va CommonJS'da ham ishlaydi.- Modul obyekti: nomli eksportlar +
default; faqat o'qish uchun; modul bir marta bajariladi va keshlanadi. - Kam ishlatiladigan kodni bosilganda yuklang; yuklash xatosini ushlang — Chrome muvaffaqiyatsiz importni qayta so'ramaydi.
- Manzil o'zgaruvchidan bo'lsa — faqat oq ro'yxat orqali:
import()— kod bajarish. - Top-level
await— faqat modullarda; uni import qilgan hamma modul kutadi — kirish faylida mayli, kutubxonada yo'q. - JSON —
with { type: "json" }bilan (Baseline 2025); CSS modullar hali Baseline emas.
Keyingi dars: fetch asoslari — serverdan haqiqiy ma'lumot olamiz: «Bahor» mashq API'sidan menyu, Response, response.ok va nega fetch 404 da rad etilmaydi. Shu paytgacha "o'ynab" kelgan server o'rinbosarlarimiz haqiqiy so'rovlarga almashadi.
Manbalar
- ECMAScript: "Import Calls", "Module Namespace Exotic Objects", "Import Attributes" — tc39.es/ecma262
- HTML Living Standard: "JSON module scripts", "CSS module scripts" — html.spec.whatwg.org
- MDN: "import()", "await — top level await", "Import attributes" — developer.mozilla.org
- Node.js 24 hujjatlari: "Modules: ECMAScript modules" (
import(), JSON modullar, import attributes) — nodejs.org/api/esm.html - web-features 3.40:
json-modules,css-modules,top-level-await— github.com/web-platform-dx/web-features
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!