Mundarija (38)
- Bu darsda
- 1. Nega bu kerak?
- 2. process — kirish va chiqishlar
- 3. process.argv — buyruq argumentlari
- 3.1 Massiv tuzilishi
- 3.2 Argumentlarni qo'lda tahlil qilish
- 4. process.env — muhit o'zgaruvchilari
- 4.1 Har doim matn
- 4.2 Windows: katta-kichik harf farq qilmaydi
- 4.3 Muhit o'zgaruvchisini berish
- 5. stdout va stderr
- 6. Exit kodlari
- 6.1 Kelishuvlar
- 6.2 process.exitCode — tinch chiqish
- 6.3 process.exit() — keskin to'xtatish
- 6.4 Node o'zi qo'yadigan kodlar
- 7. Signallar: SIGINT va SIGTERM
- 7.1 Signal nima
- 7.2 Windows topilmasi
- 8. process ning boshqa foydali qismlari
- 9. CLI qadami: valyuta loyihasi boshlanadi
- 9.1 Manba: CBU ochiq API
- 9.2 Loyiha skeleti
- 9.3 src/kurs.ts — toza model
- 9.4 src/manba.ts — tarmoq va fayl
- 9.5 src/cli.ts — process bilan ishlaydigan qism
- 9.6 Ishga tushiramiz
- 9.7 Testlar va lint topilmasi
- 9.8 O'lchov va commit
- 10. Ko'p uchraydigan xatolar
- 11. Mashqlar
- 1-mashq (oson): exit kodni tanlang
- 2-mashq (o'rta): exit kod bilan tahlil
- 3-mashq (qiyin): o'zini bola jarayon sifatida sinaydigan skript
- 4-mashq: CLI qadami — valyuta ni yarating
- 12. Real ishda
- Xulosa
- Manbalar
Node.js process obyekti: argv, env, exit kodlari va signallar
Qisqacha:
process— Node dasturining tashqi dunyo bilan aloqasi. Kirish:process.argv(buyruq qatori argumentlari, matnlar massivi) vaprocess.env(muhit o'zgaruvchilari, doim matn). Chiqish:process.stdout(natija),process.stderr(xato va ogohlantirish) va exit kod — 0 muvaffaqiyat, boshqasi xato. Kodniprocess.exitCode = 2bilan belgilang,process.exit()ni faqat zarur bo'lganda chaqiring — u ishni to'liq tugatmasdan uzadi.SIGINT(Ctrl+C) vaSIGTERMsignallariniprocess.onbilan ushlash mumkin, lekin Windows'da boshqa jarayon yuborgan signal ishlovchini chaqirmaydi (o'lchandi). Shu darsdavalyutaCLI'si boshlanadi.
Bu darsda
process.argvdan foydalanuvchi argumentlarini ajratib olasiz vaprocess.envbilan sozlama o'qiysiz.- Natijani
stdoutga, xatonistderrga yozish nega muhimligini tushuntira olasiz. - Exit kodlarini to'g'ri qo'yasiz:
exitCodevaexit()farqi,exitvabeforeExithodisalari. SIGINTni ushlab, 130 kod bilan chiqasiz va Windows'dagi cheklovni bilasiz.valyutaloyihasini noldan yaratasiz: TypeScript, ESLint,node:test, CBU kurslari, 10 ta test va birinchi commit.
Oldin bilishingiz kerak: Global obyektlar: Node va brauzer farqi, Birinchi avtomatik test: node:test, package.json III: scripts, TypeScript asoslari.
1. Nega bu kerak?
Terminalda har kuni buyruq yozasiz: git commit -m "...", npm i -D eslint. Har biri — dastur, va har biri uch narsani biladi: siz unga nima berdingiz (argumentlar), qanday muhitda ishlayapti (muhit o'zgaruvchilari) va oxirida muvaffaqiyatli tugadimi (exit kod).
Oxirgisi ko'rinmaydi, lekin juda muhim. CI tizimi testlar o'tdimi-yo'qligini aynan exit koddan biladi. npm run check ichida tip && lint && test yozilgan — && oldingi buyruqning exit kodi 0 bo'lsagina keyingisini ishga tushiradi. Exit kodi noto'g'ri bo'lgan dastur xato bilan tugasa ham, CI "hammasi yaxshi" deb o'ylaydi.
Bu darsda o'zingizning birinchi haqiqiy CLI'ingizni boshlaysiz — valyuta: Markaziy bank kurslarini terminalda ko'rsatadi va konvertatsiya qiladi. U to'g'ri argument o'qiydi, natijani to'g'ri oqimga yozadi, xatoda to'g'ri kod bilan chiqadi va Ctrl+C ga javob beradi.
O'xshatish: pochta bo'limi. Siz xat (argument) va manzil sozlamalari (muhit) bilan kelasiz. Xodim ishni bajaradi va kvitansiya beradi: "yetkazildi" yoki "manzil xato" (exit kod). Xatlarni bitta qutiga, shikoyatlarni boshqasiga soladi (stdout va stderr).
2. process — kirish va chiqishlar
process — Node'dagi global obyekt (Global obyektlar darsida ko'rdingiz). U joriy ishlayotgan jarayonni ifodalaydi. Jarayon (process) — operatsion tizimda ishlab turgan dastur nusxasi: o'z xotirasi, raqami (PID) va kirish-chiqishlari bilan.
Diagrammada jarayonning "eshiklari"ga qarang — chapda kiradigan, o'ngda chiqadigan:
flowchart LR
A["argv<br/>kurs USD"] --> P["Node jarayoni<br/>process"]
E["env<br/>VALYUTA_OFFLINE=1"] --> P
S["signal<br/>Ctrl+C"] --> P
P --> O["stdout<br/>natija"]
P --> R["stderr<br/>xato"]
P --> X["exit kod<br/>0 / 1 / 2 / 130"]Har birini navbat bilan ko'ramiz.
3. process.argv — buyruq argumentlari
3.1 Massiv tuzilishi
process.argv — matnlar massivi. Birinchi ikki element doim Node'ning o'zi va fayl yo'li. Foydalanuvchi yozgani — uchinchidan boshlab:
console.log(process.argv.slice(2));
console.log(process.argv.length);
console.log(process.execPath === process.argv[0]);node argv.mjs kurs USD --tez "100 so'm" — biz ishga tushirdik:
[ 'kurs', 'USD', '--tez', "100 so'm" ]
6
trueTo'liq massiv: [node.exe yo'li, argv.mjs yo'li, 'kurs', 'USD', '--tez', "100 so'm"] — 6 ta. Yo'llar kompyuterga bog'liq, shuning uchun deyarli har CLI process.argv.slice(2) dan boshlaydi.
Uchta qoidaga e'tibor bering:
- Hamma element — matn.
100ham"100"bo'lib keladi; songa o'zingiz aylantirasiz. - Bo'sh joy argumentlarni ajratadi. Qo'shtirnoq ichidagi
"100 so'm"bitta argument — buni terminal (shell) hal qiladi, Node emas. --tezham oddiy matn. Node bayroqlarni o'zi tahlil qilmaydi. Buning uchunutil.parseArgsbor — uni util moduli darsida ko'rasiz. Hozir qo'lda ajratamiz.
3.2 Argumentlarni qo'lda tahlil qilish
Tahlil funksiyasini process dan ajratib yozsak, uni sinash oson: massivni o'zimiz beramiz. Bu blok saytda ham ishlaydi:
function parseCommand(args) {
const [first, ...rest] = args;
if (first === undefined || first === "--help") {
return { type: "help" };
}
if (first === "kurs") return { type: "rates", codes: rest };
const amount = Number(first);
if (!Number.isFinite(amount) || rest[0] === undefined) {
const message = `Tushunarsiz: ${args.join(" ")}`;
return { type: "error", message };
}
const [from, to = "UZS"] = rest;
return { type: "convert", amount, from, to };
}
console.log(parseCommand(["kurs", "USD", "EUR"]));
console.log(parseCommand(["100", "usd"]));
console.log(parseCommand(["yuz", "usd"]));
console.log(parseCommand([]));Konsolda:
{ type: 'rates', codes: [ 'USD', 'EUR' ] }
{ type: 'convert', amount: 100, from: 'usd', to: 'UZS' }
{ type: 'error', message: 'Tushunarsiz: yuz usd' }
{ type: 'help' }Bu naqsh — valyuta ning asosi: haqiqiy dasturda parseCommand(process.argv.slice(2)) chaqiriladi, testda esa istalgan massiv. Brauzer konsoli obyektlarni biroz boshqacha ko'rsatadi ({type: 'rates', codes: Array(2)}) — ma'nosi bir xil.
4. process.env — muhit o'zgaruvchilari
4.1 Har doim matn
Muhit o'zgaruvchisi (environment variable) — jarayonga tashqaridan beriladigan nomli sozlama. Masalan PATH — terminal dasturlarni qayerdan qidirishi. Next.js'da env darsida .env fayllarini ko'rgansiz; Node'da ularning hammasi oxirida process.env ga tushadi.
process.env oddiy obyektga o'xshaydi, lekin bitta muhim farqi bor — u faqat matn saqlaydi:
process.env.KURS = 11903.15;
console.log(typeof process.env.KURS, process.env.KURS);
process.env.YOQ = undefined;
console.log(process.env.YOQ, typeof process.env.YOQ);
delete process.env.YOQ;
console.log(process.env.YOQ);Konsolda:
string 11903.15
undefined string
undefinedIkkinchi qatorga diqqat bilan qarang: undefined string. undefined ni yozganda u "undefined" degan matn bo'ldi. Endi if (process.env.YOQ) rost chiqadi! O'zgaruvchini olib tashlash uchun faqat delete. Sonli sozlamani esa har doim tekshirib o'giring: Number(process.env.PORT ?? 3000).
4.2 Windows: katta-kichik harf farq qilmaydi
Windows'da muhit o'zgaruvchilari nomi katta-kichik harfga sezgir emas. Biz ishga tushirdik:
console.log(process.env.path === process.env.PATH);trueLinux va macOS'da path va PATH — ikki xil o'zgaruvchi, natija false bo'ladi (hujjatga ko'ra; Linux'da sinalmagan). Shuning uchun nomlarni doim aynan bir xil — odatda KATTA harflar bilan yozing.
4.3 Muhit o'zgaruvchisini berish
Bitta buyruq uchun o'zgaruvchi berish shell'ga bog'liq:
| Shell | Yozilishi |
|---|---|
| Git Bash, Linux, macOS | VALYUTA_OFFLINE=1 node src/cli.ts kurs |
| PowerShell | $env:VALYUTA_OFFLINE=1; node src/cli.ts kurs |
| cmd.exe | set VALYUTA_OFFLINE=1 && node src/cli.ts kurs |
PowerShell va cmd'da o'zgaruvchi shu oyna yopilguncha qoladi. Git Bash'dagi birinchi usulda esa faqat shu bitta buyruqqa beriladi.
Tekshirib ko'ring:
if (process.env.DEBUG === true)shartiDEBUG=true node app.mjsbilan ishga tushirilganda bajariladimi?
Javob
Yo'q. process.env.DEBUG — matn "true", mantiqiy true emas. "true" === true — false. To'g'risi: process.env.DEBUG === "true" yoki === "1".
5. stdout va stderr
Jarayonning ikkita chiqish oqimi bor. console.log — process.stdout ga yozadi, console.error va console.warn — process.stderr ga. Terminalda ikkalasi ham bir ekranga chiqadi, shuning uchun farq ko'rinmaydi. Farq yo'naltirganda paydo bo'ladi:
valyuta kurs USD > kurs.txt> faqat stdout'ni faylga yozadi. Agar "Ogohlantirish: API ishlamadi" ham stdout'ga ketganida, u kurs.txt ichiga tushib, faylni buzardi. stderr'ga yozilgani esa ekranda qoladi, fayl toza.
Qoida (CLI'lar uchun umumiy kelishuv):
- stdout — faqat natija: boshqa dastur o'qishi mumkin bo'lgan ma'lumot.
- stderr — qolgan hamma narsa: xato, ogohlantirish, jarayon haqida xabar.
process.stdout.write(matn) — console.log ning soddaroq akasi: oxiriga yangi qator qo'shmaydi va obyektni formatlamaydi. valyuta aynan shuni ishlatadi — chiqishni to'liq o'zi boshqaradi.
6. Exit kodlari
6.1 Kelishuvlar
Exit kod (chiqish kodi) — jarayon tugaganda OS'ga qaytaradigan butun son. Bash'da oxirgi buyruqning kodi — echo $?, PowerShell'da — $LASTEXITCODE.
| Kod | Ma'nosi | Kim qo'yadi |
|---|---|---|
| 0 | muvaffaqiyat | sukut |
| 1 | umumiy xato; ushlanmagan istisno | Node, sizning kodingiz |
| 2 | noto'g'ri foydalanish (argument xato) | CLI kelishuvi (bash, grep) |
| 13 | tugamagan top-level await |
Node |
| 130 | Ctrl+C bilan to'xtatildi (128 + 2) | CLI kelishuvi |
| 134 | abort — masalan xotira tugadi |
Node/OS (Xotira limitlari) |
128 + N — "N raqamli signal bilan tugadi" degan Unix kelishuvi. SIGINT raqami 2, shuning uchun 130.
6.2 process.exitCode — tinch chiqish
Eng yaxshi yo'l — kodni belgilash va jarayonga o'zi tugashiga imkon berish. Bu blok exit kod 3 bilan tugaydi (tekshiruvchi buni "xato" deb ko'radi, shuning uchun faqat chiqish solishtiriladi):
process.on("beforeExit", (code) => {
console.log(`beforeExit, kod: ${code}`);
});
process.on("exit", (code) => {
console.log(`exit hodisasi, kod: ${code}`);
setTimeout(() => console.log("bu hech qachon chiqmaydi"), 0);
});
console.log("ish tugadi");
process.exitCode = 3;Konsolda:
ish tugadi
beforeExit, kod: 3
exit hodisasi, kod: 3echo $? — 3. Ikki hodisa farqi:
beforeExit— loop'da ish qolmaganda chiqadi. Bu yerda yana asinxron ish boshlash mumkin (masalan oxirgi logni yuborish) — shunda jarayon davom etadi.process.exit()chaqirilganda u chiqmaydi.exit— jarayon albatta tugayapti. Ichida faqat sinxron kod ishlaydi:setTimeoutham,awaitham bajarilmaydi — "bu hech qachon chiqmaydi" ko'rinmadi.
6.3 process.exit() — keskin to'xtatish
process.exit(kod) jarayonni darhol tugatadi — loop'da nima qolgan bo'lsa ham:
setTimeout(() => console.log("taymer ishladi"), 100);
console.log("exit() dan oldin");
process.exit(1);Konsolda:
exit() dan oldinTaymer ishlamadi. Agar u faylga yozish yoki tarmoqqa javob yuborish bo'lganida — ish yarim qolardi. Node hujjati ("A note on process I/O") ogohlantiradi: stdout ba'zi platformalarda va oqim turlarida asinxron, process.exit() hali yozilmagan ma'lumotni kesib yuborishi mumkin. Biz Windows'da 10 MB ni pipe orqali yozib exit(0) qildik — hammasi yetib keldi (10 000 000 bayt). Bu kafolat emas, faqat bitta platforma kuzatuvi. Shuning uchun:
Maslahat: Odatiy holda
process.exitCode = kodva funksiyadanreturn.process.exit()faqat chindan to'xtatish kerak bo'lganda — masalan signal ishlovchisida, tozalash tugagach.
6.4 Node o'zi qo'yadigan kodlar
Ikkita holatni bilib qo'ying. Ushlanmagan xato yoki rad etilgan Promise — kod 1:
Promise.reject(new Error("API javob bermadi"));Konsolda:
Error: API javob bermadiHech qachon tugamaydigan top-level await — kod 13. Biz ishga tushirdik:
await new Promise(() => {}); // hech qachon hal bo'lmaydi
console.log("yetib kelmaydi");Warning: Detected unsettled top-level await at file:///C:/Users/…/tla.mjs:1
await new Promise(() => {}); // hech qachon hal bo'lmaydi
^"Hal bo'lmagan top-level await aniqlandi". Loop'da kutadigan hech narsa yo'q (taymer ham, ulanish ham), Promise esa osilib qoldi — Node buni ko'rib, 13 bilan chiqadi.
Tekshirib ko'ring: CLI noto'g'ri valyuta kodi uchun xato xabarini chiqaradi, lekin exit kod 0. Bu nimaga olib keladi?
Javob
Skript yoki CI uni muvaffaqiyat deb hisoblaydi. Masalan valyuta 1 XYZ && echo saqlandi — "saqlandi" chiqadi, garchi hech narsa hisoblanmagan bo'lsa ham. Xato — nolga teng bo'lmagan kod (valyuta da noto'g'ri foydalanish uchun 2).
7. Signallar: SIGINT va SIGTERM
7.1 Signal nima
Signal — OS jarayonga yuboradigan qisqa xabar: "to'xta", "qayta yukla". Eng ko'p uchraydiganlari:
| Signal | Raqam | Qachon | Ushlash mumkinmi |
|---|---|---|---|
SIGINT |
2 | terminalda Ctrl+C | ha |
SIGTERM |
15 | "iltimos, tugat" (Docker, kill) |
ha |
SIGKILL |
9 | "darhol o'l" | yo'q |
Sukut bo'yicha Node SIGINT va SIGTERM olganda darhol tugaydi. process.on("SIGINT", fn) yozsangiz, sukut bekor bo'ladi — endi jarayonni to'xtatish sizning ishingiz. Shuning uchun ishlovchi oxirida process.exit() chaqiriladi — bu uning eng to'g'ri joyi:
process.once("SIGINT", () => {
process.stderr.write("\nTo'xtatildi\n");
process.exit(130);
});Serverlarda SIGTERM ishlovchisida ochiq ulanishlar yopiladi va keyin chiqiladi — bu "graceful shutdown" (ohista to'xtash), uni server darslarida ko'rasiz.
7.2 Windows topilmasi
Kanon tajribasi: bola jarayon SIGINT va SIGTERM uchun ishlovchi o'rnatadi va "tayyor" deydi. Ota jarayon unga child.kill(signal) yuboradi. Natija Windows 11 da:
SIGINT: stdout="tayyor", exit code=null, signal=SIGINT
SIGTERM: stdout="tayyor", exit code=null, signal=SIGTERM
SIGKILL: stdout="tayyor", exit code=null, signal=SIGKILL
process.platform: win32Uchala holatda ham "ishlovchi: SIGINT" chiqmadi — jarayon ishlovchisiz, darhol o'ldirildi. Windows'da haqiqiy Unix signallari yo'q. Node ularni taqlid qiladi: SIGINT ishlovchisi faqat konsoldagi haqiqiy Ctrl+C da chaqiriladi, boshqa dastur yuborgan "signal" esa jarayonni shunchaki tugatadi.
Halol eslatma: kanon haqiqiy Ctrl+C ni sinay olmadi — avtomatik vosita konsolga tugma bosa olmaydi. Siz CLI qadamida o'zingiz bosib ko'rasiz. Linux'da kill -INT <pid> ishlovchini chaqiradi (hujjatga ko'ra; Linux'da sinalmagan).
8. process ning boshqa foydali qismlari
| Xususiyat | Nima beradi | Misol qiymat (kanon mashinasi) |
|---|---|---|
process.cwd() |
buyruq qaysi papkadan chaqirilgani | C:/Users/…/valyuta |
process.platform |
OS | win32 (linux, darwin) |
process.pid |
jarayon raqami | har safar boshqa |
process.memoryUsage() |
rss, heapTotal, heapUsed, external, arrayBuffers |
bo'sh skript: rss 37 MB |
process.hrtime.bigint() |
nanosekundli monoton vaqt | bigint |
process.hrtime.bigint() — vaqtni o'lchash uchun. U Date.now() dan farqli: soat qo'lda o'zgartirilsa ham orqaga ketmaydi (monoton) va nanosekundgacha aniq. Natija — BigInt:
const start = process.hrtime.bigint();
JSON.parse(JSON.stringify(Array(100_000).fill({ kurs: 11903.15 })));
const ns = process.hrtime.bigint() - start;
console.log(`${Number(ns) / 1e6} ms`);performance.now() ham shunday monoton va brauzerda ham bor — ko'p hollarda u qulayroq. memoryUsage() maydonlarini Xotira limitlari darsida batafsil ko'ramiz.
9. CLI qadami: valyuta loyihasi boshlanadi
Kanon holat 08 — valyuta ning birinchi ishlaydigan versiyasi. Quyidagi hamma fayl va chiqish shu holatdan.
9.1 Manba: CBU ochiq API
Markaziy bank kurslarni kalitsiz, ochiq JSON sifatida beradi: https://cbu.uz/uz/arkhiv-kursov-valyut/json/ — 74 valyuta, 25,5 KB. Bitta yozuv (keraksiz maydonlar olib tashlangan):
{ "Ccy": "USD", "CcyNm_UZ": "AQSH dollari", "Nominal": "1",
"Rate": "11903.15", "Diff": "-62.36", "Date": "23.10.2026" }Uchta e'tiborga loyiq joy: kurs matn ("11903.15"), nominal ham matn — va u har doim 1 emas (Indoneziya rupiyasi uchun "10": kurs 10 rupiya uchun). Sana kun.oy.yil ko'rinishida.
Kanon API'ni sinab, hujjatda yo'q xulqni topdi: noma'lum valyuta uchun javob — bo'sh massiv [] va kod 200 (xato emas!). Noto'g'ri yoki kelajakdagi sana so'ralsa ham — jim ravishda oxirgi kurs. Xulosa: CLI javobni o'zi tekshiradi va foydalanuvchiga javobdagi Date ni ko'rsatadi, so'ralgan sanani emas.
9.2 Loyiha skeleti
mkdir valyuta
cd valyuta
git init
npm i -D --save-exact typescript@6.0.3 @types/node@24.19.2 \
eslint@10.12.0 @eslint/js@10.0.1 typescript-eslint@8.71.2Oxiridagi teskari chiziq buyruqni keyingi qatorda davom ettiradi (Git Bash). PowerShell'da hammasini bitta qatorga yozing.
Biz ishga tushirdik (npm 11.19.0):
added 98 packages, and audited 99 packages in 8s98 paket, 47 MB — hammasi dev bog'liqlik. valyuta ning o'zi ishlashi uchun bitta ham paket kerak emas: fetch, fs, test — hammasi Node'da bor. package.json (kanon):
{
"name": "valyuta",
"version": "0.1.0",
"description": "O'zbekiston Markaziy banki valyuta kurslari terminalda",
"type": "module",
"private": true,
"engines": {
"node": ">=24"
},
"scripts": {
"start": "node src/cli.ts",
"test": "node --test \"test/**/*.test.ts\"",
"tip": "tsc --noEmit",
"lint": "eslint . --max-warnings=0",
"check": "npm run tip && npm run lint && npm test"
},
"devDependencies": {
"@eslint/js": "10.0.1",
"@types/node": "24.19.2",
"eslint": "10.12.0",
"typescript": "6.0.3",
"typescript-eslint": "8.71.2"
}
}Muhim qarorlar:
"start": "node src/cli.ts"— build yo'q. Node 24.tsfaylni tiplarini o'chirib to'g'ridan bajaradi. Bu qanday ishlashi va chegaralari — TypeScript'ni Node'da to'g'ridan darsida."private": true— tasodifan npm'ga chiqib ketmasin. Nashrga O'z npm paketingiz darsida tayyorlaymiz; o'shanda nomni@login/valyutaga o'zgartirasiz (login— npm'dagi nomingiz). Hozir loyiha lokal, nom —valyuta."engines": { "node": ">=24" }— type stripping'siz eski Node'dasrc/cli.tsishlamaydi."type": "module"— loyiha boshidan ESM (ES Modules Node'da).
tsconfig.json:
{
"compilerOptions": {
"target": "ES2024",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"types": ["node"],
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"erasableSyntaxOnly": true,
"verbatimModuleSyntax": true,
"allowImportingTsExtensions": true,
"noEmit": true,
"skipLibCheck": true
},
"include": ["src", "test"]
}Yangi uchtasi: erasableSyntaxOnly — faqat o'chirib tashlash mumkin bo'lgan TS sintaksisi (enum yo'q), aynan Node type stripping talab qiladigani. allowImportingTsExtensions — importlarda ./kurs.ts deb yozishga ruxsat (Node aynan shu nomli faylni qidiradi). noEmit — tsc faqat tekshiradi, JS yozmaydi. Qolganlarini 15-qismda ko'rgansiz.
eslint.config.js — typescript-eslint'ning eng qat'iy to'plami (strictTypeChecked) va bitta istisno; istisnoning sababi pastda:
import js from "@eslint/js";
import { defineConfig } from "eslint/config";
import tseslint from "typescript-eslint";
export default defineConfig(
{ ignores: ["dist/", "fixtures/"] },
js.configs.recommended,
tseslint.configs.strictTypeChecked,
{ languageOptions: { parserOptions: { projectService: true } } },
{
// node:test `test()` Promise qaytaradi — runner o'zi kutadi
// (typescript-eslint hujjatidagi yechim)
rules: {
"@typescript-eslint/no-floating-promises": [
"error",
{
allowForKnownSafeCalls: [
{
from: "package",
package: "node:test",
name: ["test", "describe", "it", "suite"],
},
],
},
],
},
},
{
files: ["**/*.js"],
extends: [tseslint.configs.disableTypeChecked],
},
);.gitignore da: node_modules/, dist/, *.tgz. Fixture — fixtures/kurslar-2026-10-23.json: CBU'ning 2026-10-23 dagi haqiqiy javobi (74 yozuv). Uni kurs materiallaridan (kurs/mashqlar/24/08-process/fixtures/) oling — testlar aynan shu sana va kurslarga tayanadi. O'zingiz curl -o fixtures/kurslar.json https://cbu.uz/uz/arkhiv-kursov-valyut/json/ bilan bugungisini olsangiz, testlardagi sana va raqamlarni moslashtirasiz.
9.3 src/kurs.ts — toza model
Bu modul process, fs, tarmoqni bilmaydi — faqat ma'lumot va hisob (Global obyektlar darsidagi qoida). Kanon kodi aynan (izohlar asl):
// Kurs modeli: CBU javobini tekshirib o'qish va konvertatsiya
// (tarmoqsiz, toza funksiyalar)
export interface Kurs {
kod: string; // "USD"
nomi: string; // "AQSH dollari"
nominal: number; // 1 yoki 10, 100 (masalan IDR — 10 birlik uchun)
kurs: number; // nominal birlik necha so'm
farq: number; // kechagiga nisbatan o'zgarish
sana: string; // ISO: "2026-10-23"
}
export const SOM: Kurs = {
kod: "UZS",
nomi: "O'zbekiston so'mi",
nominal: 1,
kurs: 1,
farq: 0,
sana: "",
};
function matn(x: Record<string, unknown>, kalit: string): string {
const q = x[kalit];
if (typeof q !== "string")
throw new TypeError(
`CBU javobida "${kalit}" matn emas: ${JSON.stringify(q)}`,
);
return q;
}
function son(x: Record<string, unknown>, kalit: string): number {
const n = Number(matn(x, kalit));
if (!Number.isFinite(n))
throw new TypeError(`CBU javobida "${kalit}" son emas`);
return n;
}
/** "23.10.2026" → "2026-10-23" */
export function sanaIso(dmy: string): string {
const m = /^(\d{2})\.(\d{2})\.(\d{4})$/.exec(dmy);
if (!m) throw new TypeError(`Kutilmagan sana formati: ${dmy}`);
return `${m[3] ?? ""}-${m[2] ?? ""}-${m[1] ?? ""}`;
}
export function yozuvniOqi(x: unknown): Kurs {
if (typeof x !== "object" || x === null)
throw new TypeError("CBU yozuvi obyekt emas");
const y = x as Record<string, unknown>;
const nominal = son(y, "Nominal");
const kurs = son(y, "Rate");
if (nominal <= 0 || kurs <= 0)
throw new TypeError(
`${matn(y, "Ccy")}: kurs yoki nominal musbat emas`,
);
return {
kod: matn(y, "Ccy"),
nomi: matn(y, "CcyNm_UZ"),
nominal,
kurs,
farq: son(y, "Diff"),
sana: sanaIso(matn(y, "Date")),
};
}
export function royxatniOqi(x: unknown): Kurs[] {
if (!Array.isArray(x))
throw new TypeError("CBU javobi massiv emas");
return x.map(yozuvniOqi);
}
/** 1 birlik necha so'm */
export function birlikKursi(k: Kurs): number {
return k.kurs / k.nominal;
}
export function konvert(miqdor: number, dan: Kurs, ga: Kurs): number {
return (miqdor * birlikKursi(dan)) / birlikKursi(ga);
}
/** 11903.15 → "11 903.15"
* (minglik — bo'sh joy, kasr — nuqta, 2 xona) */
export function sonniYoz(n: number, xona = 2): string {
const [butun = "", kasr] = Math.abs(n).toFixed(xona).split(".");
const guruh = butun.replace(/\B(?=(\d{3})+(?!\d))/g, " ");
return (n < 0 ? "-" : "") + guruh + (kasr ? `.${kasr}` : "");
}Telefonda o'qish oson bo'lishi uchun bu darsdagi kanon fayllarida uzun qatorlar bo'lingan (70 belgigacha) va izohlar ikki qatorga o'tkazilgan. Mantiq kanon bilan aynan bir xil. Faqat matn shablonlari (`...`) bo'linmagan — ularni bo'lsak, chiqish o'zgaradi. Asosiy g'oyalar: tashqi ma'lumot (unknown) tekshirilib Kurs ga aylanadi, noto'g'ri yozuv tushunarli TypeError beradi. Konvertatsiya doim so'm orqali: USD → so'm → EUR.
9.4 src/manba.ts — tarmoq va fayl
// Kurslar manbasi: CBU ochiq API (kalitsiz)
// yoki fixtures/ dagi saqlangan javob
import { readFile } from "node:fs/promises";
import { royxatniOqi, type Kurs } from "./kurs.ts";
export const API = "https://cbu.uz/uz/arkhiv-kursov-valyut/json/";
export const FIXTURE = new URL(
"../fixtures/kurslar-2026-10-23.json",
import.meta.url,
);
export interface Natija {
kurslar: Kurs[];
manba: "api" | "fixture";
}
export async function apidanOl(asos = API): Promise<Kurs[]> {
const javob = await fetch(asos);
if (!javob.ok)
throw new Error(`CBU API ${String(javob.status)} qaytardi`);
return royxatniOqi(await javob.json());
}
export async function fixturedanOl(): Promise<Kurs[]> {
return royxatniOqi(JSON.parse(await readFile(FIXTURE, "utf8")));
}FIXTURE — import.meta.url ga nisbatan: CLI qaysi papkadan chaqirilsa ham fayl topiladi (Global obyektlar darsidagi cwd tuzog'i).
9.5 src/cli.ts — process bilan ishlaydigan qism
Darsning hamma tushunchasi shu faylda: argv, env, stdout/stderr, exit kodlari, signal.
#!/usr/bin/env node
// valyuta — CBU kurslari terminalda. Exit kodlar:
// 0 — muvaffaqiyat, 1 — ish vaqtidagi xato,
// 2 — noto'g'ri foydalanish, 130 — Ctrl+C
import { SOM, konvert, sonniYoz, type Kurs } from "./kurs.ts";
import { apidanOl, fixturedanOl } from "./manba.ts";
const YORDAM = `Foydalanish:
valyuta kurs [KOD...] kurslar jadvali (masalan: valyuta kurs USD EUR)
valyuta <miqdor> <KOD> [KOD] konvertatsiya (sukut bo'yicha so'mga)
Muhit o'zgaruvchilari:
VALYUTA_API API manzili (sukut: CBU)
VALYUTA_OFFLINE 1 bo'lsa — tarmoqsiz, fixtures/ dagi kurslar`;
class FoydalanishXatosi extends Error {}
async function kurslarniOl(env: NodeJS.ProcessEnv): Promise<Kurs[]> {
if (env.VALYUTA_OFFLINE === "1") return fixturedanOl();
try {
return await apidanOl(env.VALYUTA_API);
} catch (xato) {
const sabab = xato instanceof Error ? xato.message : String(xato);
process.stderr.write(
`Ogohlantirish: API ishlamadi (${sabab}) — saqlangan kurslar ishlatildi\n`,
);
return fixturedanOl();
}
}
function top(kurslar: Kurs[], kod: string): Kurs {
const k = kod.toUpperCase();
if (k === "UZS") return SOM;
const topildi = kurslar.find((x) => x.kod === k);
if (!topildi)
throw new FoydalanishXatosi(`Noma'lum valyuta: ${kod}`);
return topildi;
}
function jadval(kurslar: Kurs[]): string {
return kurslar
.map(
(k) =>
`${k.kod.padEnd(4)} ${String(k.nominal).padStart(3)} ${sonniYoz(k.kurs).padStart(12)} ${sonniYoz(k.farq).padStart(8)} ${k.nomi}`,
)
.join("\n");
}
export async function main(
argv: string[],
env: NodeJS.ProcessEnv,
): Promise<number> {
const [birinchi, ...qolgan] = argv;
if (
birinchi === undefined ||
birinchi === "--help" ||
birinchi === "-h"
) {
process.stdout.write(YORDAM + "\n");
return birinchi === undefined ? 2 : 0;
}
try {
const kurslar = await kurslarniOl(env);
if (birinchi === "kurs") {
const tanlangan = qolgan.length
? qolgan.map((kod) => top(kurslar, kod))
: kurslar;
process.stdout.write(
`${kurslar[0]?.sana ?? ""} holatiga\n${jadval(tanlangan)}\n`,
);
return 0;
}
const miqdor = Number(birinchi);
const [dan, ga = "UZS"] = qolgan;
if (!Number.isFinite(miqdor) || dan === undefined)
throw new FoydalanishXatosi(
`Tushunarsiz buyruq: ${argv.join(" ")}`,
);
const natija = konvert(
miqdor,
top(kurslar, dan),
top(kurslar, ga),
);
process.stdout.write(
`${sonniYoz(miqdor)} ${dan.toUpperCase()} = ${sonniYoz(natija)} ${ga.toUpperCase()}\n`,
);
return 0;
} catch (xato) {
if (xato instanceof FoydalanishXatosi) {
process.stderr.write(`Xato: ${xato.message}\n\n${YORDAM}\n`);
return 2;
}
process.stderr.write(
`Xato: ${xato instanceof Error ? xato.message : String(xato)}\n`,
);
return 1;
}
}
process.once("SIGINT", () => {
process.stderr.write("\nTo'xtatildi\n");
process.exit(130);
});
process.exitCode = await main(process.argv.slice(2), process.env);Darsdagi har qoida qayerda ekanini ko'ring:
| Qoida | cli.ts da |
|---|---|
argv — slice(2) |
oxirgi qator: main(process.argv.slice(2), …) |
| env — matn, aniq solishtirish | env.VALYUTA_OFFLINE === "1" |
| natija → stdout, xato → stderr | process.stdout.write / process.stderr.write |
exitCode, exit() emas |
process.exitCode = await main(...) (top-level await) |
exit() — faqat signalda |
SIGINT ishlovchisi, kod 130 |
| noto'g'ri foydalanish — 2 | FoydalanishXatosi → return 2 |
main argv va env'ni parametr sifatida oladi — process ga to'g'ridan yopishmaydi. «Argumentlarni qo'lda tahlil qilish» bo'limidagi parseCommand g'oyasi shu: testda istalgan argv va env berish mumkin. Birinchi qatordagi #!/usr/bin/env node — shebang: Unix tizimlariga "bu faylni node bilan ishga tushir" deydi. Uning ahamiyatini Workspaces darsida haqiqiy xato bilan ko'rasiz.
--help 0 qaytaradi (foydalanuvchi yordam so'radi — muvaffaqiyat), argumentsiz chaqiruv esa 2 (buyruq to'liq emas).
9.6 Ishga tushiramiz
Barcha chiqishlar haqiqiy — biz kanon holat 08 da ishga tushirdik (VALYUTA_OFFLINE=1, Git Bash):
VALYUTA_OFFLINE=1 node src/cli.ts kurs USD EUR IDR2026-10-23 holatiga
USD 1 11 903.15 -62.36 AQSH dollari
EUR 1 13 329.15 -108.12 EVRO
IDR 10 6.59 -0.06 Indoneziya rupiyasiecho $? → 0. IDR qatorida nominal 10 — 6,59 so'm 10 rupiya uchun. Konvertatsiya:
VALYUTA_OFFLINE=1 node src/cli.ts 100 usd100.00 USD = 1 190 315.00 UZSNoto'g'ri kod — stderr'ga xato va yordam, exit 2:
$ VALYUTA_OFFLINE=1 node src/cli.ts 1 XYZ
Xato: Noma'lum valyuta: XYZ
Foydalanish:
valyuta kurs [KOD...] kurslar jadvali (masalan: valyuta kurs USD EUR)
valyuta <miqdor> <KOD> [KOD] konvertatsiya (sukut bo'yicha so'mga)
Muhit o'zgaruvchilari:
VALYUTA_API API manzili (sukut: CBU)
VALYUTA_OFFLINE 1 bo'lsa — tarmoqsiz, fixtures/ dagi kurslar
$ echo $?
2Shu buyruqni 2>/dev/null bilan ishga tushirsak (stderr tashlab yuboriladi), ekran butunlay bo'sh qoladi, kod baribir 2. stdout toza — skript uchun bu to'g'ri xulq.
API ishlamasa — ogohlantirish stderr'ga va fixture. 127.0.0.1:9 — ataylab ishlamaydigan manzil (aniq sababi — fetch bu portni umuman bloklashi — Stack trace darsida ochiladi):
$ VALYUTA_API=http://127.0.0.1:9/ node src/cli.ts 1 USD
Ogohlantirish: API ishlamadi (fetch failed) — saqlangan kurslar ishlatildi
1.00 USD = 11 903.15 UZSEndi Ctrl+C ni o'zingiz sinang. Tarmoq sekin bo'lganda node src/cli.ts kurs ni ishga tushirib darhol Ctrl+C bosing. Kutilgan natija — To'xtatildi va echo $? → 130. Kanon buni avtomatik sinay olmadi (yuqoridagi Windows bo'limiga qarang) — natijangizni mashqda yozib qo'ying.
Halol eslatma:
process.exit(130)hech narsani kutmaydi. Keyingi darslardavalyutafaylga ham yozadi (Xavfsiz fayl operatsiyalari — vaqtinchalik.tmpfayl varename). Ctrl+C aynan yozish paytida bosilsa,.tmpfayl diskda qolib ketishi mumkin. Asosiy fayl buzilmaydi, lekin chiqindi qoladi. Kanon buni sinamagan — o'sha darsda yana eslaymiz.
9.7 Testlar va lint topilmasi
Ikkita test fayli, jami 10 test. test/kurs.test.ts — modelning 5 testi (nominal, xato xabarlari, format). test/cli.test.ts — CLI'ni haqiqiy jarayon sifatida ishga tushiradi va exit kod, stdout, stderr ni tekshiradi:
import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { test } from "node:test";
import { promisify } from "node:util";
const CLI = new URL(
"../src/cli.ts",
import.meta.url,
).pathname.replace(/^\/(\w:)/, "$1");
async function ishgaTushir(
args: string[],
env: Record<string, string> = { VALYUTA_OFFLINE: "1" },
) {
try {
const { stdout, stderr } = await promisify(execFile)(
process.execPath,
[CLI, ...args],
{ env: { ...process.env, ...env } },
);
return { kod: 0, stdout, stderr };
} catch (x) {
const e = x as { code: number; stdout: string; stderr: string };
return { kod: e.code, stdout: e.stdout, stderr: e.stderr };
}
}
test("noma'lum valyuta — stderr va exit 2", async () => {
const r = await ishgaTushir(["1", "XYZ"]);
assert.equal(r.kod, 2);
assert.equal(r.stdout, "");
assert.match(r.stderr, /Noma'lum valyuta: XYZ/);
});(Fayldan bitta test ko'rsatilgan; qolgan to'rttasi — kurs USD jadvali, konvertatsiya, argumentsiz/--help kodlari va API yiqilganda fixture.) execFile(process.execPath, …) — joriy Node'ning o'zi bilan bola jarayon ochish; child_process darsida chuqur ko'rasiz. Hozir g'oya muhim: CLI'ning exit kodini faqat uni alohida jarayonda ishga tushirib tekshirish mumkin.
npm run checkBiz ishga tushirdik — tip (tsc) xatosiz, lint xatosiz, test natijasining oxiri:
ℹ tests 10
ℹ suites 0
ℹ pass 10
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0Kanon topilmasi. ESLint konfiguratsiyasidagi istisno blokisiz npm run lint 10 ta xato beradi — har test(...) chaqiruvida (biz qayta ishga tushirdik, chiqish qisqartirilgan):
test\cli.test.ts
18:1 error Promises must be awaited, end with a call to .catch, end with a call to .then with a rejection handler or be explicitly marked as ignored with the `void` operator @typescript-eslint/no-floating-promises
✖ 10 problems (10 errors, 0 warnings)Tarjimasi: "Promise kutilishi, .catch bilan tugashi … yoki void bilan ataylab e'tiborsiz belgilanishi kerak". Qoida to'g'ri: osilib qolgan Promise — xato yashirinadigan joy. Lekin node:test ning test() Promise qaytaradi va uni runner o'zi kutadi. typescript-eslint hujjatidagi yechim — allowForKnownSafeCalls: "node:test paketidagi test, describe, it, suite xavfsiz". Har chaqiruvga void yozishdan ko'ra bitta konfiguratsiya qatori toza.
9.8 O'lchov va commit
Kanon tekshiruvi (tekshiruv-08.txt, Node 24.21.0, i5-12500H):
| Ko'rsatkich | Qiymat |
|---|---|
| tip / lint / test | 0 xato / 0 xato / 10 dan 10 |
| prod bog'liqlik | 0 |
| dev bog'liqlik | 5 (98 paket, 47 MB) |
sovuq start --help |
127 ms (mediana, n=10) |
sovuq start kurs USD |
171 ms |
Bo'sh Node 73 ms edi (Node.js nima) — .ts faylni tiplarini o'chirib yuklash va fixture o'qish qolgan ~50–100 ms ni oladi. Bu raqamni build bilan solishtirishni ES Modules va CJS va ESM birga darslarida (holat 12) ko'rasiz.
Commit (kanondagi xabar):
git add .
git commit -m "valyuta: CBU kurslari va konvertatsiya — argv, env, exit kodlari, Ctrl+C"10. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
Number(process.argv[1]) — NaN |
foydalanuvchi argumentlari indeks 2 dan | process.argv.slice(2) |
if (process.env.X) — "undefined" bilan ham rost |
env ga undefined yozilgan → "undefined" matni |
delete process.env.X |
| Xatoda ham exit kod 0, CI "yashil" | exitCode qo'yilmagan |
xatoda process.exitCode = 1 (yoki 2) |
| Fayl yarim yozilgan, log yo'qolgan | process.exit() asinxron ishni uzdi |
exitCode + tabiiy tugash |
| Ctrl+C ishlamay qoldi | SIGINT ishlovchisi exit chaqirmaydi |
ishlovchi oxirida process.exit(130) |
child.kill("SIGTERM") — ishlovchi chaqirilmadi (Windows) |
Windows'da Unix signallari yo'q | ohista to'xtashni boshqa kanal bilan (IPC, HTTP) qiling |
> natija.txt ichida ogohlantirish |
ogohlantirish stdout'ga yozilgan | xabarlar — stderr'ga |
11. Mashqlar
Mashqlar kurs/mashqlar/24/08-process/ da (fixture fayli ham shu yerda).
1-mashq (oson): exit kodni tanlang
valyuta kelishuvi bo'yicha qaysi kod:
valyuta kurs USDmuvaffaqiyatli —valyuta 100 ABC(bunday valyuta yo'q) —- Fixture fayli o'chirib yuborilgan, API ham ishlamadi —
- Foydalanuvchi Ctrl+C bosdi —
valyuta --help—
Yechim
- 0 — natija chiqdi.
- 2 — foydalanuvchi xatosi (
FoydalanishXatosi), yordam ham chiqadi. - 1 — ish vaqtidagi xato: buyruq to'g'ri, lekin ma'lumot olib bo'lmadi.
- 130 — 128 + 2 (
SIGINT). - 0 — yordam so'ralgan va berilgan. Argumentsiz
valyutaesa 2.
2-mashq (o'rta): exit kod bilan tahlil
«Argumentlarni qo'lda tahlil qilish» bo'limidagi parseCommand ni oling. Uning ustiga run(args) funksiyasini yozing — u { out, err, code } qaytarsin. out — stdout'ga, err — stderr'ga ketadigan matn. help → kod 0 (agar --help bo'lsa) yoki 2 (argumentsiz). error → err da xabar, kod 2. rates → out da "kurslar: USD, EUR" (kodsiz bo'lsa "kurslar: hammasi"), kod 0. convert → out da "100 USD → UZS", kod 0. To'rt holatni sinang.
Yechim
function parseCommand(args) {
const [first, ...rest] = args;
if (first === undefined || first === "--help") {
return { type: "help", asked: first === "--help" };
}
if (first === "kurs") return { type: "rates", codes: rest };
const amount = Number(first);
if (!Number.isFinite(amount) || rest[0] === undefined) {
const message = `Tushunarsiz: ${args.join(" ")}`;
return { type: "error", message };
}
const [from, to = "UZS"] = rest;
return { type: "convert", amount, from, to };
}
function run(args) {
const cmd = parseCommand(args);
switch (cmd.type) {
case "help": {
const code = cmd.asked ? 0 : 2;
return { out: "Foydalanish: ...", err: "", code };
}
case "error":
return { out: "", err: `Xato: ${cmd.message}`, code: 2 };
case "rates": {
const list = cmd.codes.join(", ") || "hammasi";
return { out: `kurslar: ${list}`, err: "", code: 0 };
}
default: {
const from = cmd.from.toUpperCase();
const line = `${cmd.amount} ${from} → ${cmd.to}`;
return { out: line, err: "", code: 0 };
}
}
}
const samples = [
["--help"], [], ["yuz", "usd"], ["kurs"], ["100", "usd"],
];
for (const args of samples) {
const r = run(args);
console.log(r.code, r.out || r.err);
}Konsolda:
0 Foydalanish: ...
2 Foydalanish: ...
2 Xato: Tushunarsiz: yuz usd
0 kurslar: hammasi
0 100 USD → UZSrun ham process ga tegmaydi — natijani qaytaradi xolos. Haqiqiy CLI'da faqat bitta joy qoladi: out ni stdout'ga, err ni stderr'ga yozish va process.exitCode = r.code. Bu bo'linish — valyuta dagi main() ning aynan o'zi.
3-mashq (qiyin): o'zini bola jarayon sifatida sinaydigan skript
salom.mjs yozing. Agar birinchi argument bola bo'lsa, u bola rolida ishlaydi: ikkinchi argument (ism) bo'lsa — stdout'ga Salom, <ism>!, kod 0; ism bo'lmasa — stderr'ga Xato: ism kerak, kod 2. SALOM_TIL=ru bo'lsa — Privet, <ism>!. Aks holda (ota rolida) u o'zini spawnSync(process.execPath, [import.meta.filename, "bola", …]) bilan uch marta ishga tushirsin va har natijani kod | stdout | stderr ko'rinishida chiqarsin.
Yechim
import { spawnSync } from "node:child_process";
const [role, name] = process.argv.slice(2);
if (role === "bola") {
if (name === undefined) {
process.stderr.write("Xato: ism kerak\n");
process.exitCode = 2;
} else {
const word = process.env.SALOM_TIL === "ru" ? "Privet" : "Salom";
process.stdout.write(`${word}, ${name}!\n`);
}
} else {
const cases = [
{ args: ["Aziz"], env: {} },
{ args: [], env: {} },
{ args: ["Malika"], env: { SALOM_TIL: "ru" } },
];
for (const c of cases) {
const r = spawnSync(process.execPath,
[import.meta.filename, "bola", ...c.args],
{ encoding: "utf8", env: { ...process.env, ...c.env } });
const [out, err] = [r.stdout.trim(), r.stderr.trim()];
console.log(`${r.status} | ${out} | ${err}`);
}
}Konsolda:
0 | Salom, Aziz! |
2 | | Xato: ism kerak
0 | Privet, Malika! |Uchta muhim joy: bola process.exitCode bilan chiqadi (exit() emas); env bolaga { ...process.env, ...c.env } bilan beriladi (aks holda PATH ham yo'qoladi); ota bola kodini r.status dan oladi. valyuta testlari aynan shu usulda ishlaydi.
4-mashq: CLI qadami — valyuta ni yarating
«CLI qadami» bo'limidagi qadamlarni bajaring: skelet, uch modul, ikki test fayli, npm run check. Keyin:
VALYUTA_OFFLINE=1 node src/cli.ts kurs USD EUR IDR— jadval kanondagi bilan bir xilmi?node src/cli.ts 1 XYZ; echo $?(PowerShell'da; $LASTEXITCODE) — 2 chiqdimi?- Ctrl+C ni sinang:
node src/cli.ts kursni ishga tushirib darhol bosing.To'xtatildiva 130 chiqdimi? Natijangizni yozib qo'ying — kanon buni sinay olmagan. - Commit:
valyuta: CBU kurslari va konvertatsiya — argv, env, exit kodlari, Ctrl+C.
Yechim
- Ha — fixture bir xil bo'lsa, jadval «Ishga tushiramiz» bo'limidagidek. Fixtureni o'zingiz olgan bo'lsangiz, sana va kurslar boshqa bo'ladi — testlarni moslang.
2. Agar 0 chiqsa —process.exitCodeqatorini tekshiring.- Tarmoq tez bo'lsa, CLI Ctrl+C ga ulgurmasdan tugaydi. Sinash uchun
VALYUTA_APIga javobi sekin manzil bering yokimainboshiga vaqtinchaawait new Promise((r) => setTimeout(r, 5000));qo'shing (keyin olib tashlang). Kutilgan:To'xtatildiva130. PowerShell'da Ctrl+C dan keyin$LASTEXITCODEham 130 bo'lishi kerak; natija boshqacha bo'lsa — yozib qo'ying, bu readline va terminal darsida asqotadi. git log --onelineda bitta commit.npm pack --dry-run— 9 fayl, 9.3 kB: test vatsconfig.jsonham paketga kirmoqda. Bu ataylab qoldirilgan kamchilik — CJS va ESM birga darsidafilesbilan tuzatamiz.
12. Real ishda
- CI va skriptlar — har CLI'ning exit kodi avtomatlashtirishning asosi.
eslint,tsc,node --testxatoda nolga teng bo'lmagan kod qaytaradi, shuning uchunnpm run checkva GitHub Actions xatoni sezadi. - Docker va Kubernetes — konteynerni to'xtatishda avval
SIGTERMyuboriladi, ~10–30 soniyadan keyinSIGKILL.SIGTERMni ushlamagan server so'rovlarni yarim yo'lda uzadi. Buni Docker qismida ko'rasiz. - 12-faktor ilova — sozlama koddan emas, muhit o'zgaruvchilaridan o'qiladi (Next.js'da env darsidagi g'oya); Node'da bu —
process.envva --env-file. - Intervyu savoli: "
process.exit()vaprocess.exitCodefarqi?" — birinchisi darhol uzadi (asinxron ish yo'qolishi mumkin), ikkinchisi kodni belgilaydi va jarayon tabiiy tugaydi.
Xulosa
process.argv.slice(2)— foydalanuvchi argumentlari, hammasi matn; tahlilni alohida funksiyaga ajrating.process.env— faqat matn;undefinedyozsangiz"undefined"bo'ladi, o'chirish —delete.- Natija — stdout, xato va ogohlantirish — stderr.
- Exit kod: 0 muvaffaqiyat, 1 xato, 2 noto'g'ri foydalanish, 130 Ctrl+C;
process.exitCodeafzal,exit()— faqat signal ishlovchisida. SIGINT/SIGTERMni ushlash mumkin,SIGKILLni yo'q; Windows'da boshqa jarayon yuborgan signal ishlovchini chaqirmaydi (o'lchandi).valyutaboshlandi: 0 prod bog'liqlik,.tsto'g'ridan Node 24 da, 10 test, birinchi commit.
Keyingi dars: Node xotira limitlari: --max-old-space-size va heap statistikasi — process.memoryUsage() raqamlari nimani bildiradi va xotira tugaganda nima bo'ladi.
Manbalar
- Node.js hujjati —
process(argv, env, exitCode, exit, events, signal events): https://nodejs.org/docs/latest-v24.x/api/process.html - Node.js hujjati — Exit codes: https://nodejs.org/docs/latest-v24.x/api/process.html#exit-codes
- Node.js hujjati — A note on process I/O: https://nodejs.org/docs/latest-v24.x/api/process.html#a-note-on-process-io
- typescript-eslint —
no-floating-promises,allowForKnownSafeCalls: https://typescript-eslint.io/rules/no-floating-promises/ - O'zbekiston Respublikasi Markaziy banki — valyuta kurslari arxivi (JSON): https://cbu.uz/uz/arkhiv-kursov-valyut/json/
- Kanon:
valyutaholat 08 (tekshiruv-08.txt), signal tajribasi (t08-signal.txt), CBU API topilmalari — Node 24.21.0, npm 11.19.0, Windows 11, i5-12500H, 2026-10-23; argv, env, exit, lint xatosi chiqishlari — yozuvchi kanon nusxasida qayta ishga tushirgan.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!