04 β Node uchun zamonaviy JavaScript va globallar¶
β¬ οΈ Oldingi: 03 β npm va package.json Β· π README Β· Keyingi: 05 β Event loop va non-blocking I/O β‘οΈ
Bu bobda: Node yozish uchun KERAK bo'ladigan zamonaviy JavaScript tushunchalarini Node kontekstida tezkor takrorlaymiz β destructuring, spread/rest, arrow funksiya va
this, shablon literallari, standart/"named" parametrlar, optional chaining?.va nullish??, eng ko'p ishlatiladigan massiv metodlari (map/filter/reduce/find) va obyekt metodlari (Object.keys/values/entries). So'ng brauzerda umuman yo'q, lekin Node'da har kuni ishlatadigan globallarga o'tamiz:process(argv/env/cwd/platform/exit/nextTick),Buffer(qisqacha),globalvsglobalThis, CommonJS'dagi__dirname/__filenameva ESM'dagiimport.meta,consolemetodlari,setTimeout/setImmediate/process.nextTick/queueMicrotaskfarqi,structuredCloneva Node 18+ dagi globalfetch. OxiridaErrorobyektlari,throw,instanceofva o'z maxsus xato sinflaringizni yozishni o'rganamiz. REAL KEYS:process.envvaprocess.argvbilan sozlanadigan kichik salomlash skripti yasaymiz.
Bu bob nima uchun va kimga?¶
JavaScript tilining o'zini bu kitobda noldan o'rgatmaymiz β buning uchun alohida JavaScript kitobi bor; agar let/const, funksiya, obyekt, massiv nima ekanini umuman bilmasangiz, avval o'sha yerga bir o'ting.
Bu bobning maqsadi boshqa: Node'ni o'rganishga kirishishdan oldin, aynan Node'da kunda ming marta uchraydigan zamonaviy JS bo'laklarini bir joyda mustahkamlash va eng muhimi β brauzerda yo'q, faqat Node'da bor narsalar (globallar) bilan tanishtirish. Keyingi boblardagi har bir misol shu tushunchalarga tayanadi: const { readFile } = await import(...), process.argv, app.use((req, res) => ...) β bularning hammasi shu yerda yotadi.
Shuning uchun bu bob ataylab amaliy va tig'iz. Har bir bo'lak bitta toza misol bilan, va har bir misol haqiqatan node bilan ishga tushadi.
π Eslatma β fayl kengaytmasi. Bu kitobda 02-bobdan boshlab asosiy uslub β ESM (import/export). Loyiha papkasida package.json ichida "type": "module" bo'lsa, oddiy .js fayl ESM bo'ladi. Agar shunday sozlama bo'lmasa, ESM uchun .mjs, CommonJS (require) uchun .cjs ishlatiladi. Bu bobdagi misollarni salom.mjs deb saqlab node salom.mjs bilan ishga tushirsangiz bo'ladi.
1-qism: Node uchun zamonaviy JavaScript¶
Destructuring β qiymatlarni "ajratib olish"¶
Destructuring obyekt yoki massivdan qiymatlarni bitta qatorda, nomi bo'yicha ajratib oladi. Node kodida bu hamma joyda uchraydi: modul import qilganda (const { readFile } = ...), funksiya parametrida, konfiguratsiya o'qiganda.
// Obyekt destructuring
const sozlama = { port: 3000, host: "localhost", debug: true };
// Eski usul β bitta-bittadan
const portEski = sozlama.port;
// Destructuring β bir qatorda
const { port, host } = sozlama;
console.log(port, host); // 3000 localhost
// Yangi nom berib olish (port -> p) va yo'q maydon uchun standart qiymat
const { port: p, vaqt = "yo'q" } = sozlama;
console.log(p, vaqt); // 3000 yo'q
Massivda esa tartib muhim (nom emas, joylashuv bo'yicha olinadi):
const ranglar = ["qizil", "yashil", "ko'k"];
const [birinchi, , uchinchi] = ranglar; // ikkinchini bo'sh joy bilan o'tkazib yubordik
console.log(birinchi, uchinchi); // qizil ko'k
Eng foydali joyi β funksiya parametrida destructuring. Node'da konfiguratsiya obyekti uzatish odatiy hol:
function ulan({ host, port, debug = false }) {
return `${host}:${port} (debug=${debug})`;
}
console.log(ulan({ port: 3000, host: "localhost", debug: true }));
// localhost:3000 (debug=true)
Spread va rest β ... uchta nuqta, ikki vazifa¶
... belgisi qayerda turishiga qarab ikki xil ishlaydi. Spread ("yoyish") mavjud narsani yoyadi; rest ("yig'ish") tarqoq narsalarni bittaga to'playdi.
// SPREAD β massivni yoyib, nusxalash va birlashtirish
const a = [1, 2, 3];
const b = [4, 5];
const birlashgan = [...a, ...b];
console.log(birlashgan); // [ 1, 2, 3, 4, 5 ]
// Obyektlarni birlashtirish β keyingisi oldingisining ustiga yoziladi
const standart = { port: 3000, debug: false };
const foydalanuvchi = { debug: true };
const yakuniy = { ...standart, ...foydalanuvchi };
console.log(yakuniy); // { port: 3000, debug: true }
Bu "obyektni yoyib, ba'zi maydonni almashtirish" usuli Node'da konfiguratsiyani standart qiymatlar bilan birlashtirishda doim ishlatiladi (REAL KEYS misolida ham ko'ramiz).
// REST β qolgan argumentlarni massivga to'plash
function yigindi(...sonlar) {
return sonlar.reduce((s, n) => s + n, 0);
}
console.log(yigindi(1, 2, 3, 4)); // 10
// Rest destructuring bilan: bosh elementni ol, qolganini massiv qil
const [bosh, ...qoldiq] = [10, 20, 30, 40];
console.log(bosh, qoldiq); // 10 [ 20, 30, 40 ]
β οΈ Muhim ogohlantirish β spread "sayoz" (shallow) nusxa qiladi. { ...obj } faqat birinchi qatlamni nusxalaydi; ichki obyektlar baham ko'riladi. Chuqur nusxa kerak bo'lsa, pastda structuredClone ni ko'ramiz.
Arrow funksiya va this β eng ko'p chalkashtiriladigan joy¶
Arrow funksiya (=>) faqat qisqa yozuv emas. Uning eng muhim xususiyati: this ni o'zi yaratmaydi β uni tashqi (leksik) qamrovdan oladi. Aynan shu xususiyat Node'dagi callback'larda hayotni yengillashtiradi.
const hisoblagich = {
son: 0,
ishga_tushir() {
// setInterval ichida ARROW ishlatamiz: 'this' baribir hisoblagich bo'lib qoladi
const id = setInterval(() => {
this.son++; // arrow tufayli 'this' = hisoblagich
console.log("son:", this.son);
if (this.son >= 3) clearInterval(id);
}, 50);
},
};
hisoblagich.ishga_tushir();
// son: 1 son: 2 son: 3
Agar setInterval ichida arrow o'rniga oddiy function () {...} yozsangiz, ichdagi this boshqa narsa bo'lib qoladi va this.son ishlamaydi:
// β Bu ishlamaydi: oddiy function() o'z 'this'ini yaratadi (hisoblagich EMAS)
setInterval(function () {
this.son++; // TypeError: Cannot read properties of undefined (reading 'son')
}, 50);
π Qoida (Node uchun): callback yozayotganda, agar tashqi thisni saqlamoqchi bo'lsangiz β arrow ishlating. Bu Node'da deyarli har doim shunday.
Shablon literallari β ${} va ko'p qatorli matn¶
Backtick (`) ichidagi matn β shablon literal. U ${...} bilan o'zgaruvchi joylashtiradi va to'g'ridan-to'g'ri ko'p qatorli bo'la oladi:
const ism = "Oqil";
const xat = `Salom, ${ism}!
Bugun ${new Date().getFullYear()}-yil.
Jami: ${2 + 3} ta xabar.`;
console.log(xat);
// Salom, Oqil!
// Bugun 2026-yil.
// Jami: 5 ta xabar.
Node'da log xabarlari, SQL/HTML matnlari, fayl yo'llari β barchasini shablon literal bilan yig'amiz.
Standart va "named" parametrlar¶
Funksiya parametriga = bilan standart qiymat beriladi: argument uzatilmasa (yoki undefined bo'lsa) o'sha qiymat ishlatiladi.
function ulan(host = "localhost", port = 3000) {
return `${host}:${port}`;
}
console.log(ulan()); // localhost:3000
console.log(ulan("db.example")); // db.example:3000
JavaScriptda Python'dagidek "named parametr" (server(port=8080)) yo'q. Lekin uning o'rniga obyekt + destructuring + standart qiymat kombinatsiyasi ishlatiladi β bu Node API'larida juda keng tarqalgan uslub:
function server({ host = "localhost", port = 3000, https = false } = {}) {
const protokol = https ? "https" : "http";
return `${protokol}://${host}:${port}`;
}
console.log(server()); // http://localhost:3000
console.log(server({ port: 8080, https: true })); // https://localhost:8080
Oxiridagi = {} muhim: u funksiyani argumentsiz chaqirsa ham (server()) ishlashini ta'minlaydi β aks holda undefined ni destructuring qilishga urinib xato berardi.
Optional chaining ?. va nullish ??¶
Bu ikki belgi Node kodini ancha xavfsiz qiladi. ?. chuqur obyektga xavfsiz murojaat qiladi: oraliq qiymat null/undefined bo'lsa, dastur qulamaydi β undefined qaytadi.
const javob = {
user: { name: "Oqil", manzil: { shahar: "Toshkent" } },
};
console.log(javob.user?.manzil?.shahar); // Toshkent
console.log(javob.user?.tel?.raqam); // undefined (xato EMAS)
// metod chaqirishda ham xavfsiz
const obj = {};
console.log(obj.salom?.()); // undefined (salom metodi yo'q, lekin qulamaydi)
?? (nullish coalescing) β faqat chap tomon null yoki undefined bo'lsagina o'ng tomonni oladi. Bu || dan farq qiladi: || esa 0, "", false larni ham "yolg'on" deb tashlab yuboradi.
const port = 0;
console.log(port ?? 3000); // 0 -> ?? faqat null/undefined'da ishlaydi, 0 saqlanadi
console.log(port || 3000); // 3000 -> || 0 ni "yolg'on" deb tashladi (XATO bo'lishi mumkin!)
const ism = undefined;
console.log(ism ?? "mehmon"); // mehmon
π Node uchun amaliy farq: process.env.PORT ?? 3000 to'g'ri (faqat o'zgaruvchi yo'q bo'lsa standartni ol), lekin agar foydalanuvchi 0 kiritsa va siz || ishlatsangiz, kutilmaganda 3000 ga tushib qolasiz. Sozlamalarda ?? ni afzal ko'ring.
Massiv metodlari: map / filter / find / reduce¶
Bu to'rtta metod Node'da ma'lumotni qayta ishlashning asosi (DB javobi, API javobi, fayl qatorlari β hammasi massiv bo'ladi). Bitta misolda hammasini ko'ramiz:
const buyurtmalar = [
{ id: 1, mahsulot: "kitob", narx: 50000, soni: 2 },
{ id: 2, mahsulot: "qalam", narx: 3000, soni: 10 },
{ id: 3, mahsulot: "daftar", narx: 8000, soni: 5 },
];
// map β har elementni o'zgartirib YANGI massiv qaytaradi
const nomlar = buyurtmalar.map((b) => b.mahsulot);
console.log(nomlar); // [ 'kitob', 'qalam', 'daftar' ]
// filter β shartga mos elementlardan yangi massiv
const qimmat = buyurtmalar.filter((b) => b.narx >= 8000);
console.log(qimmat.map((b) => b.mahsulot)); // [ 'kitob', 'daftar' ]
// find β birinchi mos elementni (yoki undefined) qaytaradi
const topildi = buyurtmalar.find((b) => b.id === 2);
console.log(topildi.mahsulot); // qalam
// reduce β hammasini bitta qiymatga "yig'ish" (bu yerda: jami summa)
const jami = buyurtmalar.reduce((sum, b) => sum + b.narx * b.soni, 0);
console.log("jami:", jami); // jami: 170000
reduce boshda qiyin tuyuladi, lekin formulasi sodda: (yig'indi, joriy) => yangi_yig'indi, va 0 β boshlang'ich qiymat. Har qadamda sumga narx * soni qo'shilib boradi.
Obyekt metodlari: Object.keys / values / entries¶
Obyekt ustidan aylanish kerak bo'lganda shu uchta metod ishlatiladi:
const sozlama = { port: 3000, host: "localhost" };
console.log(Object.keys(sozlama)); // [ 'port', 'host' ]
console.log(Object.values(sozlama)); // [ 3000, 'localhost' ]
console.log(Object.entries(sozlama)); // [ [ 'port', 3000 ], [ 'host', 'localhost' ] ]
// entries + for...of + destructuring β obyekt bo'ylab aylanishning eng toza usuli
for (const [kalit, qiymat] of Object.entries(sozlama)) {
console.log(`${kalit} = ${qiymat}`);
}
// port = 3000
// host = localhost
π Modullar (import/export) ham zamonaviy JS ning bir qismi, lekin ular shu kitobning 02-bobida to'liq yoritilgan. Bu bobdan boshlab biz asosan ESM uslubini ishlatamiz.
2-qism: Node globallari (brauzerda yo'q)¶
Brauzerda window, document, alert bor; Node'da ular yo'q. Buning o'rniga Node o'z globallarini beradi β ularni import qilish shart emas, har joyda tayyor turadi. Quyidagi xarita eng muhimlarini ko'rsatadi.
process β jarayon haqidagi hamma narsa¶
process β Node'ning eng muhim globali. U ishlab turgan jarayon (process) haqidagi ma'lumot va boshqaruvni beradi.
console.log("Node versiyasi:", process.version); // v24.12.0
console.log("Platforma:", process.platform); // win32 / linux / darwin
console.log("Arxitektura:", process.arch); // x64 / arm64
console.log("Ishchi papka:", process.cwd()); // node qaysi papkadan ishga tushgan
console.log("PID:", process.pid); // jarayon raqami
process.platform ayniqsa foydali β kodingiz Windows'da (win32), Linux'da yoki macOS'da (darwin) ishlayotganini bilib, mos yo'l ajratuvchisi yoki buyruq tanlashga yordam beradi.
process.argv β buyruq qatori argumentlari¶
process.argv β terminalda berilgan argumentlar massivi. Birinchi ikkitasi doim shu: [0] β node ning yo'li, [1] β skript fayl yo'li. Haqiqiy argumentlar [2] dan boshlanadi.
Chiqishi (yo'llar sizniki bilan farq qiladi):
Shuning uchun argumentlarni olishda deyarli doim process.argv.slice(2) qilamiz β birinchi ikkitasini tashlab.
process.env β muhit o'zgaruvchilari¶
process.env β operatsion tizimning muhit o'zgaruvchilari (environment variables). Bu β kodga tashqaridan sozlama berishning asosiy usuli: ma'lumotlar bazasi paroli, port, ish rejimi (development/production) β bularning hammasi env orqali uzatiladi (parolni kodga yozish xavfli).
console.log(typeof process.env.PATH); // string β barcha qiymat MATN bo'ladi
console.log(process.env.MENING_VAR); // undefined β agar o'rnatilmagan bo'lsa
β οΈ Diqqat: process.env ning hamma qiymatlari matn (string). process.env.PORT "3000" matn bo'ladi β son kerak bo'lsa Number(process.env.PORT) qiling.
Muhit o'zgaruvchisini bir martalik o'rnatish:
# Linux / macOS:
GREET_LANG=en node salom.mjs
# Windows PowerShell:
$env:GREET_LANG="en"; node salom.mjs
process.exit va chiqish kodi¶
process.exit(kod) jarayonni darrov to'xtatadi. 0 β muvaffaqiyat, 0 dan boshqa har qanday son β xato (bu konvensiya CI/skriptlar uchun muhim).
if (!process.env.API_KEY) {
console.error("Xato: API_KEY o'rnatilmagan");
process.exit(1); // xato kodi bilan chiqamiz
}
π Maslahat: process.exit() ni kerak bo'lmasa ishlatmang β u kutilayotgan yozish/log'larni "kesib" yuborishi mumkin. Odatda funksiyadan return qilish yoki xato throw qilish yetarli; exit faqat haqiqatan darrov to'xtash kerak bo'lganda.
process.nextTick β eng tezkor kechiktirish¶
process.nextTick(fn) callback'ni "hozirgi sinxron ish tugagach, lekin hammadan oldin" ishlatadi. Bu β Node'ning eng ustun navbati. Uni 05-bobda (event loop) chuqur ko'ramiz; hozir faqat mavjudligini bilib qo'ying:
console.log("1");
process.nextTick(() => console.log("3 (nextTick)"));
console.log("2");
// Chiqish: 1, 2, 3 β nextTick sinxron koddan keyin chaqiriladi
Buffer β binar ma'lumot (qisqacha)¶
Buffer β Node'da xom baytlar (binar ma'lumot) bilan ishlash uchun. Fayl o'qiganda, tarmoqdan ma'lumot kelganda, rasm/audio bilan ishlaganda Buffer paydo bo'ladi. Hozir faqat tanishuv β to'liq mavzu 09-bobda:
const buf = Buffer.from("Salom", "utf8");
console.log(buf); // <Buffer 53 61 6c 6f 6d> -- har belgi bayt sifatida
console.log(buf.length); // 5 -- bayt soni
console.log(buf.toString()); // Salom -- matnga qaytarish
π <Buffer 53 61 6c 6f 6d> β bu "Salom" matnining UTF-8 baytlari (53=S, 61=a, ... 16 lik sanoqda). Buffer matn EMAS, balki xom baytlar to'plami.
global vs globalThis¶
Brauzerda global obyekt window, Node'da esa global deyilardi. Bu chalkashlikni yo'qotish uchun standart globalThis nomi kiritildi β u har joyda (brauzer ham, Node ham, web worker ham) ishlaydi.
console.log(typeof globalThis); // object
console.log(globalThis === global); // true (Node'da global = globalThis)
// Barcha standart globallar globalThis ostida yashaydi
console.log(typeof globalThis.fetch); // function
console.log(typeof globalThis.setTimeout); // function
console.log(typeof globalThis.structuredClone); // function
β οΈ Global obyektga o'zingizning o'zgaruvchingizni qo'shish (globalThis.APP = ...) texnik jihatdan mumkin, lekin tavsiya etilmaydi β u modullararo yashirin bog'liqlik yaratadi va testni qiyinlashtiradi. Modullar orasida ma'lumotni import/export orqali uzating.
__dirname / __filename (CommonJS) va import.meta (ESM)¶
Joriy fayl qaysi papkada ekanini bilish ko'p kerak bo'ladi (yondosh fayl o'qish uchun).
CommonJS (.cjs yoki eski stil) da ikki sehrli o'zgaruvchi tayyor turadi:
// CommonJS β bu ikkisi tayyor
console.log(__dirname); // fayl turgan papka
console.log(__filename); // faylning to'liq yo'li
ESM (.mjs yoki "type": "module") da esa __dirname/__filename yo'q. Buning o'rniga import.meta bor:
// ESM
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
console.log(import.meta.url); // file:///C:/.../fayl.mjs (URL ko'rinishida)
// Eski uslubdagi yo'l kerak bo'lsa, URL'ni yo'lga aylantiramiz:
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
console.log(__filename, __dirname);
Yaxshi xabar: zamonaviy Node (21.2+, demak 24'da albatta) ikkita qisqa yordamchi qo'shdi β endi qo'lda aylantirish ham shart emas:
// Node 21.2+ β eng qisqa yo'l
console.log(import.meta.dirname); // fayl papkasi (oddiy yo'l)
console.log(import.meta.filename); // faylning to'liq yo'li
console metodlari β log dan ko'p narsa¶
console.log ni bilasiz, lekin console ancha kuchli:
console.log("oddiy xabar"); // stdout (asosiy chiqish)
console.error("xato xabar"); // stderr (ALOHIDA xato oqimi)
console.warn("ogohlantirish"); // stderr
// console.table β massiv/obyektlarni chiroyli jadval qilib
console.table([
{ ism: "Oqil", yosh: 25 },
{ ism: "Laylo", yosh: 30 },
]);
// console.time / timeEnd β kod qancha vaqt olganini o'lchash
console.time("hisob");
let s = 0;
for (let i = 0; i < 1_000_000; i++) s += i;
console.timeEnd("hisob"); // hisob: 3.7ms
// console.dir β chuqur obyektni to'liq ko'rsatish (depth: null)
console.dir({ a: { b: { c: { d: 1 } } } }, { depth: null });
console.table chiqishi:
βββββββββββ¬ββββββββββ¬βββββββ
β (index) β ism β yosh β
βββββββββββΌββββββββββΌβββββββ€
β 0 β 'Oqil' β 25 β
β 1 β 'Laylo' β 30 β
βββββββββββ΄ββββββββββ΄βββββββ
π log vs error farqi muhim: console.log "standart chiqish" (stdout), console.error/warn esa "xato chiqishi" (stderr) ga yozadi. Bu ikki oqim alohida; serverda log'larni faylga yo'naltirganda yoki CI'da xatolarni ajratishda shu farq qo'l keladi.
Timerlar va navbat tartibi: setTimeout / setImmediate / nextTick / queueMicrotask¶
Bu to'rttasi β "kodni keyinroq ishlatish" usullari, lekin qaysi avval ishlashi har xil. To'liq mexanika 05-bobda; bu yerda asosiy tartibni amalda ko'ramiz.
Quyidagi misolni .cjs faylga yozamiz (sof tartibni ko'rsatish uchun β sababi pastda):
// tartib.cjs
console.log("1: sinxron boshlanish");
setTimeout(() => console.log("5: setTimeout 0 (macrotask)"), 0);
setImmediate(() => console.log("6: setImmediate (check fazasi)"));
queueMicrotask(() => console.log("3: queueMicrotask (microtask)"));
Promise.resolve().then(() => console.log("4: Promise.then (microtask)"));
process.nextTick(() => console.log("2: process.nextTick (eng ustun)"));
console.log("1b: sinxron oxiri");
node tartib.cjs chiqishi:
1: sinxron boshlanish
1b: sinxron oxiri
2: process.nextTick (eng ustun)
3: queueMicrotask (microtask)
4: Promise.then (microtask)
5: setTimeout 0 (macrotask)
6: setImmediate (check fazasi)
Tartib qoidasi: sinxron kod β process.nextTick β microtask'lar (queueMicrotask/Promise.then) β macrotask'lar (setTimeout/setImmediate).
process.nextTickβ eng ustun. Cheksiz ishlatish xavfli (timer'larni "och qoldiradi" β starvation).queueMicrotask/Promise.thenβ microtask navbati;async/awaitham shu yerda.setTimeout(fn, 0)β macrotask, "kamida 0ms" (aniq emas).setImmediateβ macrotask; I/O callback ichida doimsetTimeout(0)dan oldin ishlaydi.
β οΈ Nozik nuqta (rost gap). Yuqorida .cjs ishlatdik. ESM faylning eng yuqori (top-level) qatorida nextTick Promise.then dan keyin chiqishi mumkin β sababi ESM modul tanasining o'zi bir microtask "ish"i sifatida bajariladi. Lekin callback ichida (masalan setTimeout ichida) yoki CommonJS'da klassik tartib (nextTick avval) saqlanadi. Boshlovchi sifatida shuni eslang: klassik "nextTick avval" qoidasini ishonchli ko'rish uchun kodni biror callback ichiga joylang yoki .cjs ishlating. Bu detal 05-bobda chuqur ochiladi.
structuredClone β chuqur (deep) nusxa¶
Yodingizdami, spread { ...obj } faqat sayoz nusxa qilardi va ichki obyektlar baham ko'rilardi? Mana muammo va yechimi:
const asl = { user: { ism: "Oqil", tillar: ["uz", "en"] } };
// β Spread sayoz nusxa: ichki user obyektini IKKALASI baham ko'radi
const sayoz = { ...asl };
sayoz.user.ism = "BUZILDI";
console.log(asl.user.ism); // BUZILDI -- aslni ham buzdik!
// β
structuredClone β to'liq chuqur nusxa (Node 17+ da global)
const asl2 = { user: { ism: "Oqil", tillar: ["uz", "en"] } };
const nusxa = structuredClone(asl2);
nusxa.user.tillar.push("ru"); // faqat nusxani o'zgartiramiz
console.log(asl2.user.tillar); // [ 'uz', 'en' ] -- daxlsiz
console.log(nusxa.user.tillar); // [ 'uz', 'en', 'ru' ]
structuredClone ilgari JSON.parse(JSON.stringify(obj)) "hiyla"sini almashtiradi va undan ko'ra ishonchli (sana, Map, Set, ichma-ich obyektlarni to'g'ri nusxalaydi).
Global fetch β tarmoq so'rovi, paketsiz (Node 18+)¶
Ilgari Node'da HTTP so'rov yuborish uchun axios yoki node-fetch paketini o'rnatish kerak edi. Node 18'dan boshlab fetch global β brauzerdagidek, paketsiz ishlaydi. ESM faylda top-level await ham mavjud (funksiya ichiga o'rashsiz):
// fetch-misol.mjs β paket KERAK EMAS
const res = await fetch("https://dummyjson.com/products/1");
const data = await res.json();
console.log("HTTP status:", res.status); // 200
console.log("mahsulot nomi:", data.title); // Essence Mascara Lash Princess
β οΈ Muhim: fetch faqat tarmoq butunlay ishlamaganda (internet yo'q) xato tashlaydi. Server 404 yoki 500 qaytarsa, fetch baribir "muvaffaqiyat" deb hisoblaydi β shuning uchun res.ok yoki res.status ni o'zingiz tekshirishingiz kerak. Buni xato boshqaruvi qismida (va Qiyin mashqda) ko'ramiz.
Error, throw, instanceof va maxsus xato sinflari¶
Node'da xatolarni to'g'ri boshqarish β professional kodning markazi. Xato throw qilinadi, try/catch bilan ushlanadi.
function bol(a, b) {
if (b === 0) {
throw new Error("Nolga bo'lib bo'lmaydi");
}
return a / b;
}
try {
bol(10, 0);
} catch (xato) {
console.log("xabar:", xato.message); // Nolga bo'lib bo'lmaydi
console.log("Error mi?:", xato instanceof Error); // true
console.log("nomi:", xato.name); // Error
// xato.stack -> xato qayerda yuz berganining "izi" (debug uchun oltin)
}
Haqiqiy dasturda xatoning turini ajrata olish kerak: bu validatsiya xatosimi, tarmoq xatosimi yoki kutilmagan dastur xatosi? Buning uchun Error dan meros oladigan o'z sinflaringizni yozasiz:
// Maxsus (custom) Error sinfi
class ValidatsiyaXatosi extends Error {
constructor(maydon, xabar) {
super(xabar); // ota Error konstruktoriga xabarni uzatamiz
this.name = "ValidatsiyaXatosi";
this.maydon = maydon; // qo'shimcha ma'lumot saqlaymiz
}
}
function tekshir(yosh) {
if (yosh < 0) {
throw new ValidatsiyaXatosi("yosh", "Yosh manfiy bo'lolmaydi");
}
return yosh;
}
try {
tekshir(-5);
} catch (e) {
// instanceof bilan xato TURINI farqlaymiz
if (e instanceof ValidatsiyaXatosi) {
console.log(`Validatsiya xatosi [${e.maydon}]: ${e.message}`);
// -> Validatsiya xatosi [yosh]: Yosh manfiy bo'lolmaydi
} else {
throw e; // bizniki emas -> yuqoriga uzatamiz (yutib yubormaymiz!)
}
}
π Qoida: catch blokida instanceof bilan o'zingiz kutgan xatoni boshqaring; kutmagan xatoni throw e bilan yuqoriga uzating. Xatolarni "ovsiz" yutib yuborish (catch {}) β eng ko'p uchraydigan, eng xavfli xato.
REAL KEYS: ENV va argv bilan sozlanadigan salomlash skripti¶
Endi shu bob tushunchalarini bitta hayotiy, sozlanadigan skriptga yig'amiz. Vazifa: GREET_LANG muhit o'zgaruvchisiga qarab salom tilini tanlash, ismni argument sifatida olish va --baland bayrog'i bilan matnni bosh harfga o'tkazish. Bu β real CLI asboblari (masalan generator, deploy skripti) aynan shunday sozlanadi.
// salom.mjs
// Ishlatish:
// node salom.mjs Oqil
// GREET_LANG=en node salom.mjs Oqil (PowerShell: $env:GREET_LANG="en"; ...)
// GREET_LANG=ru node salom.mjs Oqil --baland
// 1) Argumentlar: birinchi ikkitasini (node, skript) tashlaymiz
const arglar = process.argv.slice(2);
// Bayroqlarni ("--..." bilan boshlanadigan) ismdan ajratamiz
const bayroqlar = arglar.filter((a) => a.startsWith("--"));
const [ism = "mehmon"] = arglar.filter((a) => !a.startsWith("--"));
// 2) ENV'dan tilni olamiz; yo'q bo'lsa standart "uz" (?? bilan)
const til = process.env.GREET_LANG ?? "uz";
// 3) Til -> salom matnini yasovchi funksiya xaritasi
const salomlar = {
uz: (n) => `Salom, ${n}!`,
en: (n) => `Hello, ${n}!`,
ru: (n) => `Privet, ${n}!`,
};
// Optional chaining + ?? : noma'lum til kelsa, xato emas -> standart uz'ga tushamiz
const yasovchi = salomlar[til] ?? salomlar.uz;
let matn = yasovchi(ism);
// 4) --baland bayrog'i bo'lsa, bosh harfga o'tkazamiz
if (bayroqlar.includes("--baland")) {
matn = matn.toUpperCase();
}
console.log(matn);
console.log(`(til=${til}, ism=${ism}, bayroqlar=[${bayroqlar.join(", ")}])`);
Sinab ko'ramiz (PowerShell sintaksisi bilan):
node salom.mjs Oqil
# Salom, Oqil!
# (til=uz, ism=Oqil, bayroqlar=[])
# Linux/macOS: GREET_LANG=en node salom.mjs Oqil
# PowerShell: $env:GREET_LANG="en"; node salom.mjs Oqil
# Hello, Oqil!
# (til=en, ism=Oqil, bayroqlar=[])
# PowerShell: $env:GREET_LANG="ru"; node salom.mjs Oqil --baland
# PRIVET, OQIL!
# (til=ru, ism=Oqil, bayroqlar=[--baland])
# Noma'lum til -> xato emas, uz'ga tushadi:
# PowerShell: $env:GREET_LANG="fr"; node salom.mjs Laylo
# Salom, Laylo!
# (til=fr, ism=Laylo, bayroqlar=[])
Bu kichkina skriptda shu bobning deyarli hammasi ishladi: process.argv va process.env, slice/filter/includes, destructuring ([ism = "mehmon"]), standart qiymat, ??, optional chaining (salomlar[til]?.), shablon literal va arrow funksiyalar. Aynan shu β Node skriptini sozlanadigan qilishning standart yo'li.
Bu bobda nimani o'rgandik¶
- Zamonaviy JS: destructuring, spread/rest, arrow va
this, shablon literallari, standart va "obyekt-named" parametrlar,?.va??,map/filter/find/reduce,Object.keys/values/entries. - Node globallari:
process(argv/env/cwd/platform/exit/nextTick),Buffer(qisqacha),global/globalThis, CJS'da__dirname/__filename, ESM'daimport.meta,console(log/error/table/time/dir). - Kechiktirish va navbat:
setTimeout/setImmediate/process.nextTick/queueMicrotasktartibi (05-bobga ko'prik). - Zamonaviy globallar:
structuredClone(chuqur nusxa), Node 18+ dagi globalfetchva top-levelawait. - Xatolar:
Error,throw,instanceof, maxsusErrorsinflari va to'g'ricatch.
Endi siz Node kodini o'qiy olasiz va sozlanadigan skript yoza olasiz. Keyingi bobda Node'ning yuragi β event loop va non-blocking I/O bilan tanishamiz: nega bitta thread minglab so'rovni eplaydi va nextTick/setImmediate tartibi aslida qanday hal qilinadi.
Mashqlar¶
Oson¶
- Quyidagi obyektdan
nomvayoshni destructuring bilan oling,emailuchun esa"yo'q"standart qiymat bering, so'ngnodebilan tekshiring: process.argvdan foydalanib, ikki son qabul qilib ularning yig'indisini chiqaradiganqosh.mjsyozing. Ishlatish:node qosh.mjs 7 5->12. (Maslahat:process.argvqiymatlari matn,Number(...)qiling.)["olma", "anor", "uzum", "olcha"]massividan faqat"o"harfi bilan boshlanadiganlarinifilterbilan ajrating vamapbilan bosh harfli qiling (OLMA, ...).
O'rta¶
process.env.NODE_ENV ?? "development"ni o'qib, agar"production"bo'lsa "Ishlab chiqarish rejimi", aks holda "Tuzatish rejimi" chiqaradigan skript yozing.||o'rniga nega??to'g'riroq ekanini ham izohlang.- Quyidagi mahsulotlar massivida
reducebilan eng qimmat mahsulotni toping (eng kattanarxli obyektni). So'ngObject.entriesbilan g'olib obyektning har maydoninikalit = qiymatko'rinishida chop eting. - ESM faylda
import.meta.dirnamedan foydalanib, joriy fayl turgan papka yo'lini chop eting, so'ng o'sha papkaning oxirgi qismini (path.basename) ajratib chiqaring.
Qiyin¶
- Sozlama yuklovchi.
standartqiymatlar,process.env(masalanAPP_PORT,APP_HOST) vaprocess.argv(--port=9000shaklida) larni birlashtiradigan skript yozing. Ustunlik tartibi: argv > ENV > standart. Har bir qiymat qayerdan kelganini (standart/ENV/argv) ham chop eting. (Maslahat: spread bilan{ ...standart, ...env, ...argv }.) - Xato iyerarxiyasi va fetch.
AppErrorbazaviy sinfidanTarmoqXatosivaMalumotXatosini meros qiling. Globalfetchbilanhttps://dummyjson.com/products/<id>dan mahsulot oling: tarmoq umuman ishlamasaTarmoqXatosi, server404/500qaytarsaMalumotXatositashlang.id=1(bor) vaid=999999(yo'q) uchuninstanceofbilan har xil xabar chiqaring.
Yechim β 1
// mashq1.mjs
const user = { nom: "Oqil", yosh: 25, shahar: "Toshkent" };
const { nom, yosh, email = "yo'q" } = user;
console.log(nom, yosh, email); // Oqil 25 yo'q
email obyektda yo'q, shuning uchun standart qiymat ("yo'q") ishlaydi.
Yechim β 2
node qosh.mjs 7 5 -> 12. .map(Number) har bir argument matnini songa aylantiradi. Agar Number siz qo'shsangiz, "7" + "5" = "75" (matn ulanishi) bo'lib qolardi.
Yechim β 3
// mashq3.mjs
const mevalar = ["olma", "anor", "uzum", "olcha"];
const natija = mevalar
.filter((m) => m.startsWith("o"))
.map((m) => m.toUpperCase());
console.log(natija); // [ 'OLMA', 'OLCHA' ]
filter avval "o" bilan boshlanadiganlarni ajratadi, so'ng map ularni bosh harfga o'tkazadi. Metodlarni zanjirlash (.filter().map()) β Node'da odatiy.
Yechim β 4
// mashq4.mjs
const muhit = process.env.NODE_ENV ?? "development";
if (muhit === "production") {
console.log("Ishlab chiqarish rejimi");
} else {
console.log("Tuzatish rejimi");
}
?? ni ishlatamiz, chunki bu yerda faqat NODE_ENV o'rnatilmagan (undefined) bo'lsagina standart kerak. || ham shu holatda ishlardi, lekin agar kelajakda qiymat bo'sh matn ("") bo'lib qolsa, || uni ham "yolg'on" deb tashlardi β ?? esa bo'sh matnni saqlaydi. Sozlamalarda ?? xavfsizroq odat.
Yechim β 5
// mashq5.mjs
const m = [
{ nom: "kitob", narx: 50000 },
{ nom: "qalam", narx: 3000 },
{ nom: "noutbuk", narx: 9000000 },
];
// reduce: har qadamda hozirgi "g'olib"ni saqlaymiz
const golib = m.reduce((eng, joriy) => (joriy.narx > eng.narx ? joriy : eng));
console.log("eng qimmat:", golib.nom); // noutbuk
for (const [kalit, qiymat] of Object.entries(golib)) {
console.log(`${kalit} = ${qiymat}`);
}
// nom = noutbuk
// narx = 9000000
reduce ga boshlang'ich qiymat bermadik β u holda birinchi element boshlang'ich bo'ladi va taqqoslash ikkinchisidan boshlanadi. Har qadamda kattaroq narx li obyekt "g'olib" bo'lib qoladi.
Yechim β 6
// mashq6.mjs
import { basename } from "node:path";
const papka = import.meta.dirname; // Node 21.2+
console.log("to'liq papka:", papka);
console.log("oxirgi qism:", basename(papka));
import.meta.dirname joriy fayl turgan papkaning to'liq yo'lini beradi (CommonJS'dagi __dirname ekvivalenti). path.basename esa yo'lning oxirgi qismini (papka nomini) ajratadi. Eski Node'da import.meta.dirname o'rniga fileURLToPath(import.meta.url) + dirname(...) ishlatilardi.
Yechim β 7 (sozlama yuklovchi)
// config.mjs
const STANDART = { port: 3000, host: "localhost", log: "info" };
// 1) ENV'dan yig'amiz β faqat mavjudlarini
const envSozlama = {};
if (process.env.APP_PORT) envSozlama.port = Number(process.env.APP_PORT);
if (process.env.APP_HOST) envSozlama.host = process.env.APP_HOST;
if (process.env.APP_LOG) envSozlama.log = process.env.APP_LOG;
// 2) argv'dan --kalit=qiymat shaklidagilarni yig'amiz
const argvSozlama = {};
for (const arg of process.argv.slice(2)) {
const moslik = arg.match(/^--([^=]+)=(.+)$/);
if (moslik) {
const [, kalit, qiymat] = moslik;
argvSozlama[kalit] = kalit === "port" ? Number(qiymat) : qiymat;
}
}
// 3) Spread bilan birlashtiramiz β o'ng tomon ustunroq (argv eng oxirida)
const sozlama = { ...STANDART, ...envSozlama, ...argvSozlama };
console.log("Yakuniy sozlama:", sozlama);
// Manbalarni ko'rsatamiz
for (const kalit of Object.keys(STANDART)) {
let manba = "standart";
if (kalit in envSozlama) manba = "ENV";
if (kalit in argvSozlama) manba = "argv"; // argv eng ustun
console.log(` ${kalit} = ${sozlama[kalit]} (manba: ${manba})`);
}
Sinash (PowerShell):
node config.mjs
# port = 3000 (manba: standart) ...
# $env:APP_PORT="8080"; $env:APP_HOST="db.local"; node config.mjs --port=9000
# Yakuniy sozlama: { port: 9000, host: 'db.local', log: 'info' }
# port = 9000 (manba: argv) <- argv ENV'ni ham yengdi
# host = db.local (manba: ENV)
# log = info (manba: standart)
Asosiy g'oya: spread'da o'ngdagi obyekt chapdagini ustiga yozadi. { ...STANDART, ...envSozlama, ...argvSozlama } tartibida argv eng oxirida β shuning uchun u eng ustun. Bu β dotenv, commander kabi real paketlar ham qanday ishlashining soddalashtirilgan modeli.
Yechim β 8 (xato iyerarxiyasi va fetch)
// fetch-xato.mjs
class AppError extends Error {
constructor(xabar, kod) {
super(xabar);
this.name = this.constructor.name; // sinf nomini avtomatik oladi
this.kod = kod;
}
}
class TarmoqXatosi extends AppError {}
class MalumotXatosi extends AppError {}
async function mahsulotOl(id) {
let res;
try {
res = await fetch(`https://dummyjson.com/products/${id}`);
} catch (e) {
// internet umuman yo'q bo'lsa, fetch shu yerda xato tashlaydi
throw new TarmoqXatosi(`Tarmoqqa ulanib bo'lmadi: ${e.message}`, "ENET");
}
// MUHIM: 404/500'da fetch xato tashlamaydi -> o'zimiz tekshiramiz
if (!res.ok) {
throw new MalumotXatosi(`Mahsulot topilmadi (status ${res.status})`, "E404");
}
const data = await res.json();
if (!data?.title) {
throw new MalumotXatosi("Javobda 'title' maydoni yo'q", "EBAD");
}
return data.title;
}
for (const id of [1, 999999]) {
try {
const nom = await mahsulotOl(id);
console.log(`id=${id} -> ${nom}`);
} catch (e) {
if (e instanceof TarmoqXatosi) {
console.log(`id=${id} -> TARMOQ muammosi [${e.kod}]: ${e.message}`);
} else if (e instanceof MalumotXatosi) {
console.log(`id=${id} -> MALUMOT muammosi [${e.kod}]: ${e.message}`);
} else {
console.log(`id=${id} -> kutilmagan xato:`, e);
}
}
}
node fetch-xato.mjs chiqishi:
id=1 -> Essence Mascara Lash Princess
id=999999 -> MALUMOT muammosi [E404]: Mahsulot topilmadi (status 404)
Uchta muhim dars: (1) fetch faqat tarmoq darajasida xato tashlaydi β 404/500 ni res.ok bilan o'zingiz ushlaysiz; (2) Error dan meros olib, xatolarni turlarga ajratasiz; (3) instanceof bilan har bir turni alohida boshqarasiz, kutilmaganini esa yuqoriga uzatasiz. Bu β Node serverlarida xato boshqaruvining asosiy namunasi (13-bobda Express'da yana ko'ramiz).
β¬ οΈ Oldingi: 03 β npm va package.json Β· π README Β· Keyingi: 05 β Event loop va non-blocking I/O β‘οΈ