MakeFirstStep· Frontend + зеҳни сунъӣ

Дарси 18 · 🏁 Лоиҳаи хурди №2 + Кори назоратии №2

Лоиҳаи хурд: барнома дар API-и оммавӣ

Лоиҳаи дуюм барои портфолио — аллакай «калонсолона»: он барои маълумот ба интернет мераванд, боркуниро нишон медиҳад, аз хатоҳои шабака мегузарад, бо ҳар ҳарф сервер-ро бо дархостҳо пур намекунад ва тавассути Vite ба ҷамъбасти тайёр ҷамъ мешавад. Маҳз ҳамин тавр виҷетҳои обуҳаво, ҷустуҷӯи маҳсулот ва лентаҳои хабарҳо сохта шудаанд. Имрӯз шумо лоиҳаро ҳимоя мекунед, коди ҳамдигарро месанҷед ва Кори назоратии №2-ро бе ЗС менависед.

  • Варианти барномаро дар API-и оммавӣ интихоб кардан ва онро якҷоя бо ЗС ба қадамҳо тақсим намудан
  • Ҳолатҳои loading / error / empty / success-ро нишон додан ва ҷавобҳои кӯҳнаро нишон надодан
  • Дархостҳоро тавассути debounce маҳдуд кардан ва кодро ба модулҳо тақсим намудан
  • Лоиҳаро тавассути Vite ҷамъ кардан (npm run build) ва ба репозиторий бор намудан
  • Лоиҳаро дар 5 дақиқа ҳимоя кардан ва code review-ро дар ҷуфт гузаронидан
  • Кори назоратии №2-ро дар 30 дақиқа навиштан: объектҳо, async/await, fetch, коркарди хатоҳо
  • Ростқавлона таҳлил кардан, ки ЗС дар куҷо вақтро сарфа кард ва дар куҷо аз роҳ бурд
Бо ин саҳифа чӣ тавр кор кардан лозим

Имрӯз ду блок аст. Якум — лоиҳаи хурд: вазифа, меъёрҳои баҳодиҳӣ (0–100), нақша бо ЗС, ду гармкунӣ оид ба ҳолатҳо ва дархостҳо, қолаби ибтидоӣ дар майдончаи озмоишӣ, ревью дар ҷуфтҳо ва ҳимоя. Дуюм — Кори назоратии №2: дар қисми 11 версияи пурраи озмоишӣ бе ишораҳо ҷойгир аст. Барои гармкуниҳо мо ба шабакаи ҳақиқӣ намеравем: ба ҷои fetch «сервери сохта»-ро аз Promise ва setTimeout истифода мебарем — ҳамин тавр натиҷа ҳамеша яксон аст ва онро худкор санҷидан мумкин аст. Лоиҳаи худро шумо дар VS Code-и худ ҷамъ мекунед.

01 Вазифа: вариантро интихоб кунед

Лоиҳа аз он чизе ҷамъ мешавад, ки дар дарсҳои 13–17 гузаштед: ғайримуттаҳидӣ (async), fetch, ҳолатҳои боркунӣ, debounce, модулҳо ва ҷамъбасти Vite. Яке аз се вариантро интихоб кунед. Ҳамаи онҳо бо як меъёр баҳо дода мешаванд, API-ҳо ҳама кушода ҳастанд ва калид талаб намекунанд.

Варианти А. Ҷустуҷӯи маҳсулот

Майдони ҷустуҷӯ, дар зери он — кортаҳои маҳсулот. Дархост бо таъхир (debounce) мерасад, то боркунӣ меравад — нишондиҳанда, агар чизе наёфтанд — паёми фаҳмо.

API: dummyjson.com/products/search?q=phone&limit=10

Варианти Б. Обуҳаво дар шаҳрҳо

Рӯйхати шаҳрҳо (Душанбе, Хуҷанд, Бохтар, Кӯлоб ва шаҳрҳои худатон). Шаҳрро интихоб мекунед — ҳарорат ва шамолро мебинед. Хатои шабакаро бо тугма такрор кардан мумкин аст.

API: api.open-meteo.com/v1/forecast бо параметрҳои latitude, longitude, current=temperature_2m,wind_speed_10m

Варианти В. Одамон ва постҳои онҳо

Ҷустуҷӯи корбар аз рӯи ном, ҳангоми интихоб — постҳои ӯ. Ду дархости вобаста: аввал одам, баъд сабтҳои ӯ.

API: jsonplaceholder.typicode.com: /users ва /posts?userId=1

Мураккабӣ тақрибан баробар аст: дар маҳсулот мантиқи ҷустуҷӯ бештар аст, дар обуҳаво — таҳлили ҷавоби дарунҷойгир, дар корбарон — дархостҳои вобаста. Ғояи худро дар API-и кушодаи дигар пешниҳод кардан мумкин аст, агар он калид надошта бошад, аз браузер (CORS) кор кунад ва ҳаҷмаш ҳамон қадар бошад — инро бо муаллим пеш аз оғози кор мувофиқа кунед.

Монандӣ аз ҳаёт

Шумо дар чойхона тавассути пешхизмат палав фармоиш медиҳед. То он замон, ки мепазад — «фармоиш қабул шуд»-ро мебинед (loading). Агар палав нест — пешхизмат ростқавлона мегӯяд «тамом шуд» (empty), ва агар дар ошхона хатогӣ рух дод — «бубахшед, боз кӯшиш кунед» (error). Пешхизмати бад хомӯш аст ва умуман ҷавоб намедиҳад — ва шумо намедонед, интизор шавед ё равед. Барномаи шумо бояд мисли пешхизмати хуб рафтор кунад.

Дар охир чиро нишон медиҳед

  1. Барномаи корӣ — бе хато дар консол кушода мешавад, ҳангоми хомӯш будани шабака хатои ботартибро нишон медиҳад.
  2. Репозиторий дар GitHub бо коди Vite, README ва скриншот; фармони npm run build бе хато мегузарад.
  3. Ҳимояи 5-дақиқагӣ — намоиш, шарҳи код ва ҷавоб ба саволҳо.
  4. Таҳлили кӯтоҳи «ЗС дар лоиҳа» — қисми 12: ЗС дар куҷо кумак кард, дар куҷо аз роҳ бурд.
Қоидаҳои курс дар ин ҷо ҳам амал мекунанд

ЗС-ро истифода бурдан мумкин аст, аммо: аввал 15 дақиқа худатон кӯшиш мекунед, кодеро, ки сатр ба сатр фаҳмонида наметавонед, намегузоред, ва дар ҳимоя муаллим ҳақ дорад, ки хоҳиш кунад ҳар кадом сатрро фаҳмонед. Натавонистед — холҳои ин қисм кам карда мешаванд. Аммо дар Кори назоратии №2 ЗС комилан хомӯш аст.

02 Талабот: MVP ва бонусҳо

MVP — версияи ҳадди ақал, ки аллакай аз аввал то охир кор мекунад. Аввал онро пурра месозем, ва танҳо баъд оро медиҳем. Лоиҳа бе MVP баҳои баланд намегирад, ҳар қадар бонус дар он бошад ҳам.

MVP — барои ҳамаи вариантҳо ҳатмист

№ТалаботЧӣ тавр месанҷем
1Маълумот аз API-и оммавӣ тавассути fetch ва async/await меояддар ҷадвали Network дархост намоён аст, дар код маълумоти «холӣ»-и ҷойгузин нест
2Санҷиши response.ok: ҷавоби 404 ё 500 хато ҳисоб мешавад, на маълумотдар код if (!response.ok) throw … ҳаст
3Ҳолати loading: то дархост меравад — нишондиҳанда, майдон ё тугма иҷозат намедиҳанд дархости дукарата фиристода шавадSlow 3G-ро дар DevTools фаъол мекунем
4Ҳолати error: паёми фаҳмо ва тугмаи «Такрор» (такрор); барнома намеафтадOffline-ро дар DevTools фаъол мекунем
5Ҳолати empty: «Ҳеҷ чиз ёфт нашуд» ба ҷои экрани холӣдархости бемаъно ворид мекунем
6Ҷустуҷӯ ё интихоб (аз рӯи вариант) бо debounce ё тугмаи возеҳ; дархости холӣ ба сервер намеравадзуд менависем: дар Network на зиёда аз як дархост
7Ҷавоби кӯҳна ҷавоби тозаро намепӯшонад (ҳисобкунаки дархостҳо ё AbortController)дархостро зуд иваз мекунем — дар экран охирин аст, на пеш аз охирин
8Код ба модулҳои ES тақсим шудааст: api.js, ui.js (ё render.js), main.jsсохтори папкаи src/
9Лоиҳа дар Vite: npm run dev оғоз мешавад, npm run build бе хато анҷом меёбаддар ҳимоя иҷро мекунем

Бонусҳо — пас аз MVP

  • Скелетонҳо ба ҷои калимаи «Боркунӣ…» (блокҳои хокистарӣ дар зери кортаҳо).
  • Кэш-и дархостҳои охирин: ҳамон дархост бори дуюм ба шабака намеравад.
  • Таймаути дархост тавассути Promise.race ё AbortController бо паёми худӣ.
  • Таърихи ҷустуҷӯ ё интихобшудаҳо дар localStorage.
  • Такрори худкор ҳангоми хато: то се кӯшиш бо таваққуф.
  • Мавзӯи торик бо нигоҳ доштани интихоб.
  • Саҳифабандӣ ё тугмаи «Бештар нишон додан» (limit ва skip дар dummyjson).
Маслиҳат

Бонус танҳо дар сурате қадр карда мешавад, ки шумо ҳар сатри онро фаҳмонда тавонед. Як кэши оддӣ, ки шумо мефаҳмед, аз се порчаи «сеҳрноки» чати ЗС беҳтар аст.

03 Лоиҳа чӣ тавр баҳо дода мешавад (0–100)

Лоиҳаи хурд аз рӯи шкалаи 0–100 баҳо дода мешавад, чунон ки дар қоидаҳои курс навишта шудааст. Баҳо аз ҳашт меъёр ҷамъ мешавад:

МеъёрХолҳоҲадди аксарро мегузорем, агар…Қисман, агар…
Функсионалии MVP20барнома вазифаи варианти интихобшударо аз аввал то охир ҳал мекунад, дар консол хатои сурх нестсенарияи асосӣ кор мекунад, аммо хатогиҳо ҳастанд ё як қисми бандҳо нест
fetch ва async/await20дархости ҳақиқӣ ба API-и оммавӣ, await дар ҷои даркорӣ меистад, response.ok санҷида мешавад, ҷавоб тавассути await response.json() таҳлил мешавад, хатоҳоро try/catch мегираддархост кор мекунад, аммо 404 хато ҳисоб намешавад ё try/catch расмист
Ҳолатҳои loading / error / empty15ҳар се ҳолат ҳаст, аз як объекти ҳолат иваз мешаванд, «Такрор» ҳаст, дархости дукарата ғайриимкон астяке-дуи аз се ҳаст, ё ҳолатҳо «часпида мемонанд» (пас аз хато маълумоти кӯҳна мемонад)
Debounce ва назорати дархостҳо10дархостҳо бо debounce маҳдуданд, дархости холӣ фиристода намешавад, ҷавоби кӯҳна ҷавоби тозаро намепӯшонадdebounce ҳаст, аммо рақобати ҷавобҳо ҳал нашудааст
Модулҳо ва сохтор10модулҳои ES бо сарҳадҳои фаҳмо (api ба DOM даст намезанад, ui ба шабака намеравад), функсияҳои кӯтоҳ, такрор ва коди мурда нестмодулҳо ҳастанд, аммо «ҳама дар main.js» ё функсияҳои ҳаюло
Ҷамъбаст ва репозиторий5npm run build мегузарад, репозиторийи оммавӣ, README бо скриншот, ≥ 5 commit-и бомаъноҷамъбаст кор мекунад, аммо README холӣ ё commit «ҳама як порча»
Интерфейс5ботартиб, дар телефон хонда мешавад (320–400 px), :hover ва :focus ҳаст, тугмаҳо ҳангоми дархост қуфл мешавандкор мекунад, аммо монанди нусхаи пешакӣ менамояд
Ҳимоя15дар 5 дақиқа ҷо шуданд, сенарияро нишон доданд (аз ҷумла хато ва натиҷаи холӣ), порчаҳои асосиро фаҳмониданд ва ба саволҳо ҷавоб додандбо суханони умумӣ мефаҳмонед, дар «ин сатрро фаҳмон» гум мешавед
ҲАМАГӣ100

Бонусҳо то +5 хол илова мекунанд, вале натиҷа аз 100 зиёд шуда наметавонад.

Чӣ холҳоро кам мекунад

  • Коди худро фаҳмонда наметавонед — дар меъёре, ки қисми нофаҳмо ба он тааллуқ дорад, холҳоро гум мекунед.
  • Маълумот «сахт дар код навишта шудааст» ба ҷои дархости ҳақиқӣ — меъёри «fetch ва async/await» 0 мегирад.
  • Дар муҳлат супурда нашуд — то −10 хол, бо мувофиқа бо муаллим.
  • Код пурра аз донишҷӯи дигар ё аз чат бе фаҳмиш нусха шудааст — 0 барои лоиҳа. Ба якдигар кумак кардан мумкин ва лозим аст, аммо ҳар кас аз они худро менависад ва мефаҳмад.

Ин ба баҳои ниҳоии курс чӣ тавр таъсир мекунад

Ҷузъи курсВазнЧӣ тавр ҳисоб мешавад
Ҳозиршавӣ15%ҳиссаи дарсҳои ҳозиршуда
Вазифаҳои хонагӣ30%холи миёна барои 24 вазифаи хонагӣ (0–10)
Лоиҳаҳои хурд (2 адад)25%миёна барои лоиҳаи хурди 1 ва 2 (0–100)
Лоиҳаи ниҳоӣ30%ҳимоя дар дарси 21 (0–100)

Барои сертификат бояд ҳарду лоиҳаи хурдро супурд. Кори назоратии №2 — санҷиши алоҳидаи дониш: он нишон медиҳад, ки шумо рамзи ғайримуттаҳидро бе ЗС мефаҳмед, ва бо муаллим таҳлил мешавад (ниг. қисми 11).

ХолҳоБаҳо
90–100Аъло
75–89Хуб
60–74Қаноатбахш
камтар аз 60Аттестатсия нашудааст

04 Таҷзия: лоиҳаро якҷоя бо ЗС ба қисмҳо тақсим мекунем

Лоиҳа бо API аз якумӣ хатарноктар аст: шабака, интизорӣ ва хатоҳо пайдо шуданд, ки «бо фармоиш» такрор намешаванд. Барои ҳамин нақша махсусан муҳим аст. Ғоя ҳамон аст, ки дар дарси 12: аввал қадамҳо, баъд код, ва ҳар қадам натиҷаи намоён дорад. Аммо акнун дар нақша бояд қадамҳои алоҳида барои ҳар ҳолат (loading, error, empty) ва барои ҷойҳои «хатарнок» бошад: дархости аввал, рақобати ҷавобҳо, ҷамъбаст.

Монандӣ аз ҳаёт

Сафар бо маршрутка аз Душанбе ба Хуҷанд: бояд пешакӣ истгоҳҳо, вақти роҳ ва варианти эҳтиётиро донист, агар роҳро бандад. «Ба ягон тарз меравам» — роҳ ба ҳеҷ ҷо. Нақша бо варианти эҳтиётӣ — ин ҳолатҳои error ва «Такрор»-и шумост.

Блоки ЗС: вазифаи калон — маълум нест аз куҷо оғоз кардан

ЗС рӯйхати қадамҳоро хуб пешниҳод мекунад, аммо тартиб, зиёдатӣ ва баҳодиҳии вақтро шумо месанҷед. Дархостро аз рӯи формулаи курс тартиб диҳед: контекст → вазифа → маҳдудиятҳо → формати ҷавоб → санҷиш.

бо JS барномаи обуҳаво бисоз
Контекст: ман донишҷӯи курси JavaScript ҳастам, лоиҳаи таълимии «обуҳаво дар шаҳрҳои Тоҷикистон»-ро бо JS-и тоза + Vite месозам, бе фреймворкҳо. API: open-meteo (бе калид). Аллакай медонам: fetch, async/await, try/catch, ҳолатҳои loading/error/empty, debounce, модулҳои ES. Вазифа: лоиҳаро ба 10–14 қадам, ҳар кадом 20–40 дақиқа, бо тартиби иҷро тақсим кун. Маҳдудиятҳо: бе китобхонаҳо; модулҳои api.js, ui.js, main.js; дар MVP — интихоби шаҳр, дархост, се ҳолат, тугмаи «Такрор», муҳофизат аз ҷавобҳои кӯҳна. Бонусҳо — рӯйхати алоҳида дар охир. Код нанавис. Формати ҷавоб: рӯйхати рақамгузорӣшуда. Барои ҳар қадам: ном, пас аз он чӣ бояд кор кунад, баҳои вақт бо дақиқа. Санҷиш: пас аз рӯйхат 3 ҷойро номбар кун, ки навомӯз дар кор бо fetch бештар хато мекунад, ва чӣ тавр онҳоро пай бурдан мумкин аст.

Дархости аввал маҷмӯи тасодуфии калимаҳо ё фавран тамоми кодеро медиҳад, ки шумо фаҳмонида наметавонед. Дуюм — нақшае, ки бо он кор кардан мумкин аст. Аммо ин танҳо нусхаи пешакӣ аст. Мисоли нақша пас аз таҳрири шумо:

Мисоли нақша барои варианти Б (≈ 5 соат)

№ҚадамВақтПас аз он чӣ кор мекунад
1Лоиҳаи Vite, сохтори src/api.js, ui.js, main.js20 дақnpm run dev саҳифаи холиро мекушояд
2Нишонагузорӣ: интихоби шаҳр, блоки натиҷа, блоки ҳолат25 дақсаҳифа мисли барнома менамояд, аммо «мурда» аст
3api.js: getWeather(city) бо fetch ва санҷиши ok35 дақфунксияро аз консол даъват карда, маълумотро дидан мумкин аст
4Объекти state ва функсияи getView(state)25 дақҳар ҳолат матни худро медиҳад
5ui.js: render(state)30 дақҳолати дастӣ гузошташуда тасвир мешавад
6main.js: зеркунӣ ба шаҳр → loading → success30 дақобуҳаво дар саҳифа пайдо мешавад
7Шохаи error + тугмаи «Такрор»30 дақдар реҷаи Offline — хато, пас аз «Такрор» ҳама кор мекунад
8Ҳолати empty (шаҳр бе маълумот) ва қуфл кардани тугмаҳо ҳангоми дархост25 дақзеркунии дукарата ду дархост эҷод намекунад
9Муҳофизат аз ҷавобҳои кӯҳна (requestId)25 дақиваз кардани зуд-зуди шаҳрҳо охиринро нишон медиҳад
10Услубҳо, версияи мобилӣ, фокус35 дақдар 360 px хуб менамояд
11Санҷиши дастӣ: Slow 3G, Offline, маълумоти партов30 дақдар консол хато нест
12npm run build, санҷиши npm run preview20 дақҷамъбаст аз папкаи dist кор мекунад
13README, скриншот, репозиторий30 дақлоиҳа тавассути истинод дастрас аст

Бо ҷавоби ЗС чӣ кор мекунед — қадам ба қадам

  1. Зиёдатиро хат занед. «React-ро пайваст кун», «Redux-ро танзим кун», «сервери худро бинавис» — ба лоиҳаи мо дахл надорад.
  2. Тартибро санҷед. Ҳолати error-ро пеш аз он ки худи state бошад, тасвир кардан мумкин нест. Ҳар қадам ба қадамҳои пешини тайёр такя мекунад.
  3. Вақтро худатон баҳо диҳед. ЗС суръати шуморо намедонад: баҳои ӯро ба 1.5 зарб кунед. Қадаме, ки аз 40 дақиқа дарозтар аст — тақсим кунед.
  4. Ҳар қадам натиҷаи намоён медиҳад. «Бо API фаҳмидан» — қадам нест. «getWeather("Душанбе") ҳарорат дар консол бармегардонад» — қадам аст.
  5. Қадамҳоро барои «обуҳавои бад» илова кунед: Offline, ҷавоби 404, натиҷаи холӣ. ЗС аксар вақт онҳоро фаромӯш мекунад — ин соҳаи масъулияти шумост.
  6. Нақшаро дар PLAN.md сабт кунед ва иҷрошударо қайд намоед.

Амал: нақшаро бо воситаҳои JavaScript ҳисоб мекунем

ВАЗИФАИ 4.1

Лоиҳа чӣ қадар вақт мегирад

осон

Массиви қадамҳо бо баҳои вақт бо дақиқа дода шудааст. Маҷмӯъро ҳисоб кунед ва сатри намуди Всего: 185 мин = 3.1 ч-ро чоп намоед. Соатҳоро то як рақами баъд аз вергул мудаввар кунед (toFixed(1)).

Таҳрир кардан мумкин аст · Ctrl + Enter
const plan = [
  { title: "Разметка и стили", min: 30 },
  { title: "Функция fetch и разбор ответа", min: 40 },
  { title: "Состояния loading / error / empty", min: 40 },
  { title: "Debounce для поиска", min: 25 },
  { title: "Разбивка на модули", min: 30 },
  { title: "Сборка Vite и проверка build", min: 20 },
];

// маҷмӯи дақиқаҳоро ҳисоб кунед ва сатри ниҳоиро чоп намоед
Натиҷаи интизоршаванда
Всего: 185 мин = 3.1 ч
Ишора 1

Маҷмӯи майдонҳои массиви объектҳоро reduce бо қимати ибтидоии 0 ҷамъ мекунад.

Ишора 2

plan.reduce((sum, step) => sum + step.min, 0). Соатҳо — ин total / 60 аст, ва .toFixed(1) як рақами баъд аз вергулро мегузорад.

ВАЗИФАИ 4.2

Хатарноктарин қадамҳо

миёна

Дар қадамҳои хатарнок risky: true меистад. Онҳоро аз рӯи кам шудани вақт бо формати Рискованно: Название (N мин) чоп кунед, ва дар охир — Рискованных: N. Массиви аслиро тағйир додан мумкин нест.

Таҳрир кардан мумкин аст · Ctrl + Enter
const plan = [
  { title: "Разметка", min: 20, risky: false },
  { title: "Первый запрос к API", min: 40, risky: true },
  { title: "Обработка ошибок сети", min: 35, risky: true },
  { title: "Стили", min: 25, risky: false },
  { title: "Отмена устаревших запросов", min: 30, risky: true },
];

// филтр кунед, нусхаро мураттаб намоед, чоп кунед
Натиҷаи интизоршаванда
Рискованно: Первый запрос к API (40 мин)
Рискованно: Обработка ошибок сети (35 мин)
Рискованно: Отмена устаревших запросов (30 мин)
Рискованных: 3
Ишора 1

filter массиви нав бармегардонад, барои ҳамин sort пас аз он plan-и аслиро дахл намекунад.

Ишора 2

Мураттабсозӣ аз рӯи камшавӣ: .sort((a, b) => b.min - a.min). Баъд forEach бо сатри-қолаб ва .length барои ҷамъбаст.

ВАЗИФАИ 4.3

Дақиқаҳо аз рӯи марҳалаҳо

миёна

Объекти «марҳала → маҷмӯи дақиқаҳо»-ро ҷамъ кунед ва онро тавассути JSON.stringify чоп намоед. Тартиби калидҳо — аз рӯи пайдошавии аввали марҳала дар массив.

Таҳрир кардан мумкин аст · Ctrl + Enter
const plan = [
  { phase: "api", min: 40 },
  { phase: "ui", min: 30 },
  { phase: "api", min: 35 },
  { phase: "build", min: 20 },
  { phase: "ui", min: 25 },
];

// const byPhase = plan.reduce(...)
// console.log(JSON.stringify(byPhase));
Натиҷаи интизоршаванда
{"api":75,"ui":55,"build":20}
Ишора 1

Қимати ибтидоии reduce — объекти холии {}. Ҳамчун калид item.phase хизмат мекунад.

Ишора 2

acc[item.phase] = (acc[item.phase] || 0) + item.min; return acc;

05 Гармкунии 1. Ҳолатҳои дархост ва хатоҳои шабака

Ҳар дархост ба шабака дар яке аз чор ҳолат зиндагӣ мекунад: idle (ҳанӯз напурсидаанд), loading (интизорем), success (гирифтем, ва маълумот метавонад ҳам бо мазмун, ҳам холӣ бошад) ва error (нашуд). Қоидаи асосӣ: ҳамаи инҳо дар як объекти state меистанд, ва саҳифа аз он тасвир мешавад, мисли лоиҳаи №1.

Ҳолати дархост — як объект · Ctrl + Enter
const state = {
  status: "loading",   // "idle" | "loading" | "success" | "error"
  items: [],           // маълумот (ҳангоми success)
  error: "",           // матни хато (ҳангоми error)
};

// барои ҳар статус — «экран»-и худ
const screens = {
  idle: "Введите запрос",
  loading: "Загрузка...",
  success: "Показываем данные",
  error: "Что-то пошло не так",
};
console.log(screens[state.status]);

Барои бе интернет машқ кардан мо серверро бо функсияи худамон иваз мекунем: он низ Promise бармегардонад ва бо таъхир ҷавоб медиҳад — айнан мисли fetch, аммо ҳар дафъа яксон.

Сервери сохта: Promise + setTimeout · Ctrl + Enter
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// «сервер» пас аз 20 мс ҷавоб медиҳад; ба дархости "error" меафтад
async function fakeApi(query) {
  await wait(20);
  if (query === "error") throw new Error("Сеть недоступна");
  return [`${query} 1`, `${query} 2`];
}

async function main() {
  console.log("запрос...");
  const items = await fakeApi("плов");
  console.log("получили:", items.join(", "));
  try {
    await fakeApi("error");
  } catch (err) {
    console.log("ошибка:", err.message);
  }
}
main();

fetch-и ҳақиқӣ: пас аз ҷавоб чиро санҷидан лозим

fetch маккорона сохта шудааст: он танҳо дар сурате «меафтад» (промисро рад мекунад), ки умуман бо сервер алоқа кардан нашуд — шабака нест, домен ёфт нашуд. Аммо ҷавоби 404 Not Found ё 500 Server Error — ин аз нигоҳи fetch ҷавоби муваффақ аст: сервер ҷавоб дод-ку! Барои ҳамин пас аз await fetch(...) ҳамеша response.ok-ро санҷед.

Қолаби дархост — онро дар лоиҳа истифода баред
async function getJson(url) {
  const response = await fetch(url);                       // 1. ҷавобро интизор мешавем
  if (!response.ok) {                                      // 2. 404 / 500 — ҳам хато
    throw new Error(`HTTP ${response.status}`);
  }
  return await response.json();                            // 3. таҳлили JSON-ро интизор мешавем
}

async function load() {
  try {
    const data = await getJson("https://jsonplaceholder.typicode.com/users/1");
    console.log(data.name);
  } catch (err) {
    console.log("Ошибка:", err.message);                   // шабака афтод ЁКИ статус на 2xx
  }
}

Дархости ҳақиқиро кӯшиш кунед. Ин ягона блоки саҳифа аст, ки ба шабака мераваду барои ҳамин санҷиши худкор надорад: натиҷа аз API вобаста аст.

Дархости зинда (интернет лозим аст) · Ctrl + Enter
async function getJson(url) {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  return await response.json();
}

getJson("https://jsonplaceholder.typicode.com/users/1")
  .then((user) => console.log("Пользователь:", user.name))
  .catch((err) => console.log("Ошибка:", err.message));

getJson("https://jsonplaceholder.typicode.com/users/99999")   // чунин чиз нест → 404
  .then((user) => console.log("Пользователь:", user.name))
  .catch((err) => console.log("Ошибка:", err.message));
Монандӣ аз ҳаёт

Шумо ба Хуҷанд баста фиристодед. «Тамоман нарасонданд» (шабака нест) — мушкили фаҳмо. Аммо ҳолати дуюм ҳам ҳаст: бастаро курьер қабул кард, аммо дар нуқтаи расонидан гуфтанд «чунин нишонӣ нест» (404). Курьер кор кард, аммо натиҷа нест. response.ok — ин санҷиши «курьер омад ё не» нест, балки «ӯ чӣ овард».

Се хатои классикӣ

1. await-ро пеш аз fetch ё response.json() фаромӯш кардан — ба ҷои маълумот шумо Promise мегиред. 2. response.ok-ро нагирифтан — саҳифа ҷавоби хаторо «бо муваффақият» нишон медиҳад. 3. Хаторо коркард накардан — барнома хомӯшона дар «Боркунӣ…» овезон мемонад.

Ин код хато медиҳад · Ctrl + Enter
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const fakeFetch = async () => { await wait(10); return { ok: true, json: async () => ({ name: "Плов" }) }; };

async function load() {
  const response = fakeFetch();         // await-ро фаромӯш кардем
  const data = await response.json();   // TypeError: response.json is not a function
  console.log(data.name);
}
load().catch((err) => console.log("Ошибка:", err.message));

Муфассалтар хонед: learn.javascript.ru — Fetch · MDN — Response.ok · learn.javascript.ru — try…catch

Амал: мустаҳкам мекунем

ВАЗИФАИ 5.1

Экран барои ҳар ҳолат

осон

getView(state)-ро анҷом диҳед. Қоидаҳо: idle → Введите запрос; loading → Загрузка...; error → Ошибка: <матн>; success бо рӯйхати холӣ → Ничего не найдено, вагарна Найдено: N.

Таҳрир кардан мумкин аст · Ctrl + Enter
function getView(state) {
  // анҷом диҳед
}

const states = [
  { status: "idle", items: [], error: "" },
  { status: "loading", items: [], error: "" },
  { status: "success", items: [], error: "" },
  { status: "success", items: [{ id: 1 }, { id: 2 }], error: "" },
  { status: "error", items: [], error: "Сеть недоступна" },
];
states.forEach((s) => console.log(getView(s)));
Натиҷаи интизоршаванда
Введите запрос
Загрузка...
Ничего не найдено
Найдено: 2
Ошибка: Сеть недоступна
Ишора 1

Навиштани занҷири return-ҳои барвақтӣ қулай аст: if (state.status === "idle") return "…"; ва ғайра.

Ишора 2

Барои success state.items.length === 0-ро санҷед. Барои error сатри қолабиро бо state.error истифода баред.

ВАЗИФАИ 5.2

loadResults: loading → success / error

миёна

async function loadResults(api, query, onChange)-ро нависед. Аввал он onChange-ро бо ҳолати { status: "loading", items: [], error: "" } даъват мекунад. Баъд api(query)-ро интизор мешавад: ҳангоми муваффақият onChange-ро бо success ва items-и гирифташуда, ҳангоми хато — бо error ва матни err.message даъват мекунад (items — массиви холӣ). Хато ба берун намеафтад.

Таҳрир кардан мумкин аст · Ctrl + Enter
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
const okApi = async (q) => { await wait(10); return [`${q}-1`, `${q}-2`]; };
const badApi = async () => { await wait(10); throw new Error("Сервер упал"); };

// async function loadResults(api, query, onChange) { ... }

const log = (s) => console.log(`[${s.status}] items=${s.items.length} error="${s.error}"`);

async function main() {
  await loadResults(okApi, "плов", log);
  await loadResults(badApi, "плов", log);
}
main();
Натиҷаи интизоршаванда
[loading] items=0 error=""
[success] items=2 error=""
[loading] items=0 error=""
[error] items=0 error="Сервер упал"
Ишора 1

Чорчӯба: onChange-ро бо loading даъват кардем, баъд try { const items = await api(query); … } catch (err) { … }.

Ишора 2

Дар catch: onChange({ status: "error", items: [], error: err.message });. await-ро пеш аз api(query) фаромӯш накунед.

ВАЗИФАИ 5.3

Хатогиро ёбед: fetch бе await ва бе ok

миёна

Функсияи getTitle бояд сарлавҳаро баргардонад, ва барои нишонӣ, ки 404 ҷавоб медиҳад, — сатри Ошибка: HTTP 404. Ҳоло он коре мекунад, ки лозим нест. Се хаторо ёбед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const fakeFetch = (url) => new Promise((resolve) => setTimeout(() => {
  if (url.endsWith("/missing")) {
    resolve({ ok: false, status: 404, json: async () => ({ message: "Not Found" }) });
  } else {
    resolve({ ok: true, status: 200, json: async () => ({ title: "Плов" }) });
  }
}, 10));

async function getTitle(url) {
  try {
    const response = fakeFetch(url);
    const data = response.json();
    return data.title;
  } catch (err) {
    return "Ошибка: " + err.message;
  }
}

async function main() {
  console.log(await getTitle("/dishes/1"));
  console.log(await getTitle("/dishes/missing"));
}
main();
Натиҷаи интизоршаванда
Плов
Ошибка: HTTP 404
Ишора 1

Бо ҳамин ҳол иҷро кунед: ҳарду даъват як хатои якхела дар бораи json медиҳанд. Яъне response — ҷавоб нест, чизи дигар аст. Чӣ?

Ишора 2

await пеш аз fakeFetch(url) ва пеш аз response.json() лозим аст, ва дар байни онҳо — if (!response.ok) throw new Error(`HTTP ${response.status}`);.

ВАЗИФАИ 5.4

Рақобати ҷавобҳо: дархости охирин мепирӯзад

душвор

Корбар зуд «п», баъд «пл» менависад. Ҷавоб ба «п» аз ҷавоб ба «пл» (10 мс) суст (50 мс) меояд ва натиҷаи тозаро мепӯшонад. onInput(q)-ро тавре анҷом диҳед, ки ба state.text танҳо ҷавоб ба дархости охирин афтад. Ғоя: ҳар дархост рақами худро дорад; ҷавобро танҳо дар сурате татбиқ мекунем, ки рақам кӯҳна нашуда бошад.

Таҳрир кардан мумкин аст · Ctrl + Enter
const delays = { "п": 50, "пл": 10 };
const search = (q) => new Promise((resolve) =>
  setTimeout(() => resolve(`результаты для "${q}"`), delays[q]));

const state = { text: "" };
let latestId = 0;

async function onInput(q) {
  // анҷом диҳед: рақами дархост, await search(q), танҳо ҷавоби тозаро татбиқ кунед
  // ҳангоми татбиқ console.log("применён: " + q)-ро чоп кунед
}

onInput("п");
onInput("пл");
setTimeout(() => console.log(state.text), 100);
Натиҷаи интизоршаванда
применён: пл
результаты для "пл"
Ишора 1

Дар аввали функсия: const myId = ++latestId;. Тағйирёбандаи myId рақами маҳз ҳамин даъватро ба ёд мегирад.

Ишора 2

Пас аз const text = await search(q); if (myId !== latestId) return;-ро санҷед — ин ҷавоби кӯҳна аст. Вагарна state.text = text-ро нависед ва сатрро чоп кунед.

06 Гармкунии 2. Debounce, кэш ва таймаут

Агар барои ҳар ҳарфи пахшшуда дархост фиристем, сервер даҳҳо муроҷиати зиёдатӣ мегирад, ва экран милт-милт мекунад. Debounce инро ҳал мекунад: функсия танҳо вақте кор мекунад, ки корбар барои вақти додашуда хомӯш шуд. Ҳар даъвати нав таймерро аз сифр мекунад ва навашро оғоз менамояд.

debounce: пас аз таваққуф кор мекунад · Ctrl + Enter
function debounce(fn, ms) {
  let timer;
  return (...args) => {
    clearTimeout(timer);                           // таймери гузаштаро бекор кардем
    timer = setTimeout(() => fn(...args), ms);     // навашро оғоз кардем
  };
}

const search = debounce((q) => console.log("запрос:", q), 30);
search("п");
search("пл");
search("плов");      // танҳо ҳамин даъват кор мекунад, пас аз 30 мс
Монандӣ аз ҳаёт

Лифт дар офис намеравад, то даме ки касе ба он медарояд: ҳар даромада таймери баста шудани дарро «аз нав мекунад». Дарҳо танҳо вақте баста мешаванд, ки якчанд сония касе надаромад. Debounce — ҳамон дарҳост.

Модулҳо ва ҷамъбаст: чӣ дар куҷост

Дар лоиҳаи Vite код дар якчанд файл зиндагӣ мекунад — модулҳои ES. Ҳар файл он чизеро, ки дигарон лозим доранд, экспорт мекунад (export) ва бегонаро import менамояд (import). Қоидаи хуби сарҳадҳо: api дар бораи DOM намедонад, ui дар бораи шабака намедонад, main онҳоро пайваст мекунад.

Сохтори лоиҳа
product-search/
├─ index.html          ← подключает <script type="module" src="/src/main.js">
├─ package.json        ← скрипты dev / build / preview
├─ src/
│  ├─ api.js           ← только fetch и разбор ответа
│  ├─ ui.js            ← только DOM: render(state)
│  ├─ utils.js         ← debounce и мелкие помощники
│  ├─ main.js          ← состояние, события, связывает всё
│  └─ style.css
└─ dist/               ← появляется после npm run build (в Git не кладём)
src/api.js — танҳо маълумот, бе DOM
export async function searchProducts(query, signal) {
  const url = `https://dummyjson.com/products/search?q=${encodeURIComponent(query)}&limit=10`;
  const response = await fetch(url, { signal });
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  const data = await response.json();
  return data.products;
}
src/main.js — модулҳоро пайваст мекунад
import { searchProducts } from "./api.js";
import { render } from "./ui.js";
import { debounce } from "./utils.js";

const state = { status: "idle", items: [], error: "" };
// … ҳодисаи input → debounce(search, 400) → searchProducts → render(state)
Терминал
npm create vite@latest product-search -- --template vanilla
cd product-search
npm install
npm run dev        # режим разработки, адрес вида http://localhost:5173
npm run build      # собирает проект в папку dist
npm run preview    # открывает собранную версию — проверьте её перед защитой
Хатои маъмул

Танҳо npm run dev-ро санҷидан. Ҷамъбаст сахттар аст: хатои имлоӣ дар роҳи import (./Api.js ба ҷои ./api.js) дар компютери шумо метавонад кор кунад, аммо npm run build меафтад. Пеш аз ҳимоя ҳамеша build ва preview-ро иҷро кунед.

Муфассалтар хонед: learn.javascript.ru — модулҳо · learn.javascript.ru — Promise API · MDN — AbortController

Амал: мустаҳкам мекунем

ВАЗИФАИ 6.1

debounce-ро нависед

миёна

debounce(fn, ms)-ро нависед: функсияеро бармегардонад, ки fn-ро бо аргументҳои охирин танҳо пас аз таваққуф дар ms миллисония даъват мекунад.

Таҳрир кардан мумкин аст · Ctrl + Enter
// function debounce(fn, ms) { ... }

const calls = [];
const search = debounce((q) => { calls.push(q); console.log("запрос:", q); }, 30);

search("п");
search("пл");
search("плов");
console.log("сразу:", calls.length);

setTimeout(() => search("чой"), 80);
setTimeout(() => console.log("всего запросов:", calls.length), 150);
Натиҷаи интизоршаванда
сразу: 0
запрос: плов
запрос: чой
всего запросов: 2
Ишора 1

Таймер дар тағйирёбандае дар берун аз функсияи баргардонидашаванда нигоҳ дошта мешавад (let timer;), то ки он байни даъватҳо «ба ёд монад».

Ишора 2

Дар дохили функсияи баргардонидашаванда: clearTimeout(timer); timer = setTimeout(() => fn(...args), ms);

ВАЗИФАИ 6.2

Кэши дархостҳо

миёна

makeCached(api)-ро нависед: функсияи ғайримуттаҳид (async) бармегардонад, ки дархостро ба намуди trim().toLowerCase() меорад, ва агар чунин дархост аллакай буд — ҷавоби нигоҳдошташударо бе муроҷиат ба api медиҳад.

Таҳрир кардан мумкин аст · Ctrl + Enter
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
let apiCalls = 0;
const api = async (q) => { apiCalls++; await wait(10); return q.toUpperCase(); };

// function makeCached(api) { ... }

const cached = makeCached(api);
async function main() {
  console.log(await cached("Плов"));
  console.log(await cached("  плов "));
  console.log(await cached("чой"));
  console.log("вызовов API:", apiCalls);
}
main();
Натиҷаи интизоршаванда
ПЛОВ
ПЛОВ
ЧОЙ
вызовов API: 2
Ишора 1

const cache = new Map();-ро дар берун аз функсияи баргардонидашаванда эълон кунед. Калид — дархости муътадилшуда.

Ишора 2

if (cache.has(key)) return cache.get(key); вагарна const value = await api(key); cache.set(key, value); return value;

ВАЗИФАИ 6.3

Ҷавоби API → кортаҳо

миёна

API объекти маҳсулотро баргардонд. toCards(data)-ро нависед: танҳо маҳсулоти мавҷударо (stock > 0) монед, аз рӯи нарх бо тартиби афзуда мураттаб кунед (массиви аслиро тағйир надиҳед), сатрҳои намуди Чехол — 50 сом. (★ 4.8)-ро баргардонед. Рейтинг — бо як рақами баъд аз вергул.

Таҳрир кардан мумкин аст · Ctrl + Enter
const apiData = {
  total: 4,
  products: [
    { id: 1, title: "Телефон", price: 2500, rating: 4.46, stock: 5 },
    { id: 2, title: "Наушники", price: 300, rating: 3.9, stock: 0 },
    { id: 3, title: "Чехол", price: 50, rating: 4.8, stock: 20 },
    { id: 4, title: "Зарядка", price: 120, rating: 4.1, stock: 7 },
  ],
};

// function toCards(data) { ... }

const cards = toCards(apiData);
cards.forEach((c) => console.log(c));
console.log(cards.length, apiData.products[0].title);
Натиҷаи интизоршаванда
Чехол — 50 сом. (★ 4.8)
Зарядка — 120 сом. (★ 4.1)
Телефон — 2500 сом. (★ 4.5)
3 Телефон
Ишора 1

Занҷир: data.products.filter(...) → .sort(...) → .map(...). filter аллакай нусха месозад, барои ҳамин массиви аслиро sort тағйир намедиҳад.

Ишора 2

Деструктуркунӣ дар map қолабро содда мекунад: ({ title, price, rating }) => `${title} — ${price} сом. (★ ${rating.toFixed(1)})`.

ВАЗИФАИ 6.4

Таймаути дархост тавассути Promise.race

душвор

withTimeout(promise, ms)-ро нависед: агар promise дар ms миллисония ба анҷом нарасид — натиҷа бо хатои Таймаут рад мешавад, вагарна қимати промис баргардонида мешавад. Promise.race-ро истифода баред.

Таҳрир кардан мумкин аст · Ctrl + Enter
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
const fast = () => wait(20).then(() => "быстро");
const slow = () => wait(200).then(() => "медленно");

// function withTimeout(promise, ms) { ... }

async function main() {
  for (const fn of [fast, slow]) {
    try {
      console.log(await withTimeout(fn(), 100));
    } catch (err) {
      console.log("Ошибка:", err.message);
    }
  }
}
main();
Натиҷаи интизоршаванда
быстро
Ошибка: Таймаут
Ишора 1

Promise.race([a, b]) ҳамон тавр ба анҷом мерасад, ки ягон аз промисҳое, ки аввал ба анҷом расид. Промиси дуюмро «таймер-бомба» кунед.

Ишора 2

new Promise((_, reject) => setTimeout(() => reject(new Error("Таймаут")), ms)) — ин «бомба» аст.

07 Санҷиш пеш аз ҳимоя: package.json ва ҷамъбаст

Вақте npm run build-ро иҷро мекунед, Vite фармони build-ро дар бахши scripts-и файли package.json меёбад, ҳамаи модулҳоро ба якчанд файл ҷамъ мекунад ва ба папкаи dist мегузорад. Маҳз ҳамин папкаро ба хостинг мегузоранд. Дар .gitignore бояд node_modules ва dist бошанд: онҳоро дар репозиторий нигоҳ доштан лозим нест, бо фармонҳои npm install ва npm run build барқарор мешаванд.

Чек-листи «барои ҳимоя омодаам»

☐ npm install дар папкаи тоза мегузарад · ☐ npm run dev барномаро мекушояд · ☐ npm run build бе хато ва огоҳӣ · ☐ npm run preview ҳамонро нишон медиҳад · ☐ дар консоли браузер сурх нест · ☐ дар Network дархостҳо ба API-и ҳақиқӣ мераванд · ☐ дар Offline хато нишон дода мешавад, на экрани сафед.

Амал: мустаҳкам мекунем

ВАЗИФАИ 7.1

package.json-ро бихонед

осон

Матни файли package.json дода шудааст. Онро тавассути JSON.parse таҳлил кунед ва ҳар скриптро бо формати npm run ном → фармон чоп намоед, баъд Зависимостей: N — дар devDependencies ҳамагӣ чанд баста ҳаст.

Таҳрир кардан мумкин аст · Ctrl + Enter
const text = `{
  "name": "product-search",
  "private": true,
  "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" },
  "devDependencies": { "vite": "^7.0.0" }
}`;

// JSON-ро таҳлил кунед ва натиҷаро чоп намоед
Натиҷаи интизоршаванда
npm run dev → vite
npm run build → vite build
npm run preview → vite preview
Зависимостей: 1
Ишора 1

const pkg = JSON.parse(text); — акнун pkg.scripts объекти оддӣ аст.

Ишора 2

Ҷуфтҳои «калид — қимат»-ро Object.entries(pkg.scripts) медиҳад. Шумораи бастаҳо — Object.keys(pkg.devDependencies).length.

08 Қолаби ибтидоӣ: ҷустуҷӯ бо ҳолатҳо

Дар зер — скелети барнома бо ҷустуҷӯ дар майдончаи озмоишӣ. То ки натиҷа ҳамеша яксон бошад, ба ҷои сервери ҳақиқӣ дар он «сохта» (fakeSearch) истифода шудааст; ва дар паҳлӯ realSearch бо fetch-и ҳақиқӣ меистад — дар лоиҳаи худ шумо онро бо як сатр ҷойгузин мекунед. Код ба блокҳо бо ҳамон тартибе тақсим шудааст, ки шарҳ додани он дар ҳимоя қулай аст: «сервер» → ҳолат → DOM ва тасвир → ҷустуҷӯ → ҳодисаҳо.

  1. «Сервер». Маълумот ва функсияҳое, ки промис бармегардонанд: сохта ва ҳақиқӣ.
  2. Ҳолат. Як объекти { status, items, error } ва ҳисобкунаки дархостҳои latestId.
  3. Тасвир. render() интерфейсро аз state месозад. Дигар касе ба DOM даст намезанад.
  4. Ҷустуҷӯ. search(query): loading → success ё error, ҷавобҳои кӯҳна нодида гирифта мешаванд.
  5. Ҳодисаҳо. Майдони ворид бо debounce.

▶ Иҷро кардан-ро пахш кунед: худсанҷии поён чоп мекунад, ки ҳоло чӣ кор намекунад. Вазифаи шумо — чор қайди TODO.

Амал: барномаи ибтидоиро месозем

ВАЗИФАИ 8.1

TODO-ро анҷом диҳед — ва ҷустуҷӯ кор мекунад

душвор

Дар script.js чор қайдро амалӣ кунед: 1) debounce, 2) getStatusText, 3) search (дархости холӣ ба сервер намеравад; ҳолатҳо; муҳофизат аз ҷавобҳои кӯҳна; хато ба берун намеафтад), 4) коркунандаи input бо debounce. Блоки худсанҷии поён худаш дар майдон «менависад» ва натиҷаро ба консол мебарорад. Вақте ҳама тайёр аст, дар консол бояд дақиқан ҳамон чизе бошад, ки дар «Натиҷаи интизоршаванда». Блоки худсанҷиро ба лоиҳаи худ нусха накунед.

Ҷустуҷӯи ибтидоии маҳсулот · Ctrl + Enter
<main class="app">
  <h1>Поиск товаров</h1>
  <input id="q" placeholder="Например: телефон" autocomplete="off">
  <p id="status" class="status"></p>
  <ul id="results"></ul>
</main>
Пешнамоиш
Барои дидани натиҷа «Иҷро кардан»-ро пахш кунед.
Натиҷаи интизоршаванда
старт: Введите запрос
сразу после ввода: Введите запрос
через 70 мс: Загрузка...
ответ: Найдено: 4 | 4
пусто: Ничего не найдено
ошибка: Ошибка: Сеть недоступна
очистили: Введите запрос
Ишора 1

Қолабро бо ҳамин ҳол иҷро кунед ва баромадро бо интизоршаванда муқоиса намоед: сатрҳое, ки мувофиқат намекунанд, ишора мекунанд, ки кадом TODO-ро минбаъд ҳал кардан лозим. Аз getStatusText оғоз кунед — ин аз ҳама соддатар аст.

Ишора 2

search: const myId = ++latestId;, санҷиши дархости холӣ, setState({ status: "loading", ... }), баъд try бо await searchApi(query) ва санҷиши if (myId !== latestId) return; пас аз await (ва ҳамон дар catch). Коркунанда: const debouncedSearch = debounce(search, DEBOUNCE_MS); берун аз шунаванда, ва дар дохил — debouncedSearch(input.value);.

Чӣ тавр қолабро ба лоиҳаи худ гузаронидан

  1. Лоиҳаро дар Vite эҷод кунед (қисми 06) ва кодро ба модулҳо тақсим намоед: fakeSearch/realSearch — ба api.js, debounce — ба utils.js, getStatusText ва render — ба ui.js, ҳолат ва ҳодисаҳо — ба main.js.
  2. Ба ҳар файл export/import илова кунед. render акнун state-ро ҳамчун аргумент мегирад — тағйирёбандаҳои глобалӣ байни модулҳо намегузаранд.
  3. fakeSearch-ро ба realSearch иваз кунед ва дар ҷадвали Network боварӣ ҳосил намоед, ки дархостҳо ҳақиқианд.
  4. Блоки худсанҷиро хориҷ кунед.
  5. Агар шумо аллакай лоиҳаи худии дарсҳои 15–17-ро дошта бошед — онро напартоед, балки бо схемаи «ҳолат → render → search → ҳодисаҳо» муқоиса кунед.

09 Амал дар дарс: ревью, ҳимояҳо, кори назоратӣ

Имрӯз машғулот аз муқаррарӣ дигартар сохта шудааст: лоиҳаҳо қариб тайёранд, барои ҳамин вақт ба санҷиш, ҳимоя ва кори назоратӣ сарф мешавад. Мувофиқи нақша амал мекунем.

  1. 0–10 дақ · Санҷиши охирин. Чек-листи қисми 07: npm run build, preview, Offline, Slow 3G. Муаллим тартиби ҳимояҳоро тасдиқ мекунад.
  2. 10–30 дақ · Code review дар ҷуфтҳо. Барои ҳар лоиҳа 10 дақиқа. Ревьюер аз рӯи чек-листи поён мегузарад ва мулоҳизаҳоро сабт мекунад, муаллиф гӯш мекунад. Баъд ҷой иваз мекунед.
  3. 30–60 дақ · Ҳимояҳо. Ҳар кадом — 5 дақиқа ва як дақиқа барои иваз кардан. Дигарон гӯш мекунанд ва савол медиҳанд. Имрӯз натавонистед — дар аввали машғулоти оянда ҳимоя мекунед.
  4. 60–90 дақ · Кори назоратии №2. 30 дақиқа, барои ҳама якбора, бе ЗС. Тафсилот — дар қисми 11. Таҳлили хатоҳои маъмул — дар охир.
Агар лоиҳа ҳанӯз тайёр нест

Бонусҳо илова накунед. Қолаби ибтидоиро аз қисми 08 кушоед, чор TODO-ро анҷом диҳед, build-ро санҷед ва README илова кунед. Лоиҳаи содда, ки кор мекунад, аз лоиҳаи мураккаби нопурра беҳтар аст.

Code review: чек-листи ревьюер

Code review — ин вақте аст, ки як таҳиягар кодро аз таҳиягари дигар пеш аз он ки «ба олам барояд» мехонад. На имтиҳон ва на ҷустуҷӯи гунаҳкор: нигоҳи тоза он чизеро мебинад, ки муаллиф дигар пай намебарад. Формулаи мулоҳиза: дар куҷо (файл ва сатр) → чӣ мебинам → чаро муҳим аст → пешниҳод (беҳтараш бо савол).

Мешиканем (иҷро)

  • ☐ Реҷаи Offline: барнома хато ва «Такрор»-ро нишон медиҳад, на экрани сафед
  • ☐ Slow 3G: нишондиҳанда намоён аст, тугмаҳо иҷозат намедиҳанд дархости дукарата фиристода шавад
  • ☐ Дархости бемаъно: паёми «Ҳеҷ чиз ёфт нашуд»
  • ☐ Зуд менависем: дар Network на зиёда аз як дархост барои як «таваққуф»
  • ☐ Дархостро зуд иваз мекунем: дар экран ҷавоб ба охирин аст, на ба пеш аз охирин
  • ☐ Пас аз хато ва «Такрор» маълумоти кӯҳна «намечаспад»
  • ☐ Сатри холӣ ба сервер намеравад
  • ☐ Матн аз API ҳамчун матн нишон дода мешавад (textContent)
  • ☐ Дар паҳноии 360 px ҳама чиз хонда мешавад; дар консол сурх нест

Код мехонем

  • ☐ Як объекти state бо статус, на маҷмӯи парчамҳои isLoading, isError…
  • ☐ Пас аз fetch санҷиши response.ok меистад
  • ☐ Ҳар ҷое ки лозим аст, await ҳаст; промиси «фаромӯшшуда» нест
  • ☐ try/catch дар гирди дархост ва паёми бомаъно, на catch-и холӣ
  • ☐ Модулҳо: api ба DOM даст намезанад, ui ба шабака намеравад
  • ☐ debounce як бор навишта шудааст ва аз нав истифода мешавад
  • ☐ Сатрҳои статусҳо ба собитҳо бароварда шудаанд
  • ☐ Коди шарҳшуда, console.log ва функсияҳои мурда нестанд
  • ☐ Дар репозиторий node_modules ва dist нестанд
ЗС ҳамчун ревьюери дуюм — пас аз одамон, на ба ҷои онҳо

Вақте ҷуфт ба анҷом расид, кодро аз ЗС гузаронед: «Аз рӯи чек-лист санҷ: коркарди хатоҳои fetch, рақобати ҷавобҳо, сарҳадҳои модулҳо, номҳо. Танҳо мулоҳизаҳо, бе аз нав навиштани код». На ҳамаи маслиҳатҳоро қабул кунед: ҳар ислоҳро шумо бояд асоснок карда тавонед.

Муфассалтар хонед: learn.javascript.ru — ислоҳи хато дар браузер

Амал: ревью дар миниатюра

ВАЗИФАИ 9.1

Мулоҳизаи ревьюер: хато маълумотро тоза намекунад

миёна

Ревьюер навишт: «Пас аз хато дар экран натиҷаҳои кӯҳна мемонанд, ва пас аз муваффақият — матни кӯҳнаи хато». applyResult-ро ислоҳ кунед: ҳангоми error — items массиви холӣ мешавад, ҳангоми success — error сатри холӣ мешавад.

Таҳрир кардан мумкин аст · Ctrl + Enter
function applyResult(state, result) {
  if (result.error) {
    return { ...state, status: "error", error: result.error };
  }
  return { ...state, status: "success", items: result.items };
}

let s = { status: "idle", items: [], error: "" };
s = applyResult(s, { items: ["плов", "чой"] });
console.log(s.status, s.items.length, JSON.stringify(s.error));
s = applyResult(s, { error: "Сеть недоступна" });
console.log(s.status, s.items.length, JSON.stringify(s.error));
s = applyResult(s, { items: ["самбуса"] });
console.log(s.status, s.items.length, JSON.stringify(s.error));
Натиҷаи интизоршаванда
success 2 ""
error 0 "Сеть недоступна"
success 1 ""
Ишора 1

Ҳар ҳолат бояд пурра бошад: ҳангоми иваз шудани статус майдонҳоеро, ки ба статуси нав дахл надоранд, тоза кунед.

Ишора 2

Ба шохаи хато items: [], ва ба шохаи муваффақият — error: "" илова кунед.

ВАЗИФАИ 9.2

Мулоҳизаи ревьюер: хатои имлоӣ дар статус

осон

Статуси «Загрузка» нишон дода намешавад — ревьюер хатои имлоиро гумон мекунад. Онро ислоҳ кунед, ва дар баробар статусҳоро ба собити STATUS (IDLE, LOADING, SUCCESS, ERROR) бароред ва онро ҳама ҷо истифода баред: ҳамин тавр хатои имлоӣ ба хатое табдил меёбад, ки муҳаррир пай мебарад.

Таҳрир кардан мумкин аст · Ctrl + Enter
function badge(status) {
  if (status === "loadin") return "⏳ Загрузка";
  if (status === "error") return "⚠ Ошибка";
  if (status === "success") return "✓ Готово";
  return "…";
}

console.log(badge("idle"));
console.log(badge("loading"));
console.log(badge("error"));
console.log(badge("success"));
Натиҷаи интизоршаванда
…
⏳ Загрузка
⚠ Ошибка
✓ Готово
Ишора 1

Сатри дар шартро бо сатре, ки ҳангоми даъват мегузаронанд, муқоиса кунед: онҳо бояд то ҳарф мувофиқ бошанд.

Ишора 2

const STATUS = { IDLE: "idle", LOADING: "loading", SUCCESS: "success", ERROR: "error" }; — ва ҳама ҷо STATUS.LOADING ба ҷои сатр.

10 Ҳимоя: 5 дақиқае, ки 15 холро ҳал мекунад

Ҳимоя — ин ҳикояи кӯтоҳ дар бораи он, ки шумо чӣ кардед ва ин чӣ тавр кор мекунад. На презентатсия ва на бозпурсӣ: бояд нишон диҳед, ки лоиҳа аз они шумост ва шумо онро мефаҳмед. Барои ҳамин ба он 15 хол аз 100 ҷудо шудааст. Дар ин ҷо шумо на танҳо «вақте ҳама хуб аст», балки «обуҳавои бад»-ро ҳам нишон медиҳед: Offline ва натиҷаи холӣ.

Сенария барои 5 дақиқа

ВақтЧӣ кор мекунед
0:00–0:30Муаррифӣ. Бо як ибора: ин кадом барнома аст, кадом API. «Ин ҷустуҷӯи маҳсулот дар dummyjson аст: калима менависӣ — пас аз ним сония кортаҳоро мебинӣ».
0:30–2:00Намоиш. Ҷустуҷӯ → натиҷаи холӣ → Offline дар DevTools → хато ва «Такрор» → ҳама боз кор мекунад. preview-и версияи ҷамъшударо кушоед.
2:00–3:30Код. Се ҷой: getJson/api.js (fetch + ok), объекти state ва render, debounce. Бо суханони худатон шарҳ диҳед.
3:30–5:00Саволҳо. Намедонед — ростқавлона бигӯед ва тахмин кунед, ки ҷавобро чӣ тавр меҷустед.

Саволҳои маъмул ва дар бораи чӣ гуфтан лозим

async/await чист ва аз then чӣ фарқ дорад?
Ин ҳамон Promise аст, аммо код аз боло ба поён хонда мешавад. await функсияро то ҷавоб «таваққуф мекунад», бе қуфл кардани саҳифа.
Барои чӣ response.ok лозим аст? Магар fetch дар 404 намеафтад?
Не: fetch танҳо ҳангоми мушкили шабака рад мекунад. Ҷавоби 404/500 — «муваффақ» аст, зеро сервер ҷавоб дод. Статусро худатон бояд санҷед.
Барои чӣ await response.json(), ин ахир аллакай ҷавоб аст?
Сарлавҳаҳо омаданд, аммо баданаи ҷавоб алоҳида ва ҳамчунин ғайримуттаҳид хонда мешавад.
Debounce чист ва барои чӣ дар ин ҷо лозим аст?
Функсия пас аз таваққуф кор мекунад. Бе он ҳар ҳарф — дархост: сарбории зиёдатӣ ва экрани «милтилдеанда».
Рақобати ҷавобҳо чист ва шумо онро чӣ тавр ҳал кардед?
Ҷавоб ба дархости кӯҳна метавонад дертар аз ҷавоб ба дархости нав расад ва онро бипӯшонад. Ҳал: рақами дархост (танҳо тозаро татбиқ мекунем) ё AbortController.
Ҳолатҳои шумо чӣ тавр сохта шудаанд?
Як объекти state бо status, items, error; render аз он тасвир мекунад. Маҷмӯи парчамҳое нест, ки метавонанд бо якдигар зиддият кунанд.
Дар api.js чӣ ҳаст, дар ui.js чӣ, ва барои чӣ ин тавр?
Дар api.js танҳо шабака, дар ui.js танҳо DOM, main.js пайваст мекунад. Ҳамин тавр ҳар қисмро алоҳида тағйир додан ва санҷидан мумкин аст.
npm run build чӣ кор мекунад ва дар dist чӣ меистад?
Vite модулҳоро ба файлҳои барои хостинг тайёр ҷамъ мекунад. dist-ро ба Git намегузоранд: онро аз нав ҷамъ кардан мумкин аст.
ЗС-ро дар куҷо истифода кардед? Ин сатрро шарҳ диҳед.
Ростқавлона бигӯед, барои чӣ (нақша, шарҳи хато, ревью) ва дар куҷо ӯ хато кард — қисми 12. Ҳар сатрро бояд бо суханони худатон шарҳ диҳед.

Маслиҳатҳо барои омодагӣ

  • Намоишро бо овози баланд бо секундомер такрор кунед. Offline дар DevTools → Network → «No throttling» → Offline фаъол мешавад.
  • Файлҳои даркориро пешакӣ кушоед, ҳуруфро калон кунед: гурӯҳ бояд кодро бубинад.
  • Зиёдатиро хориҷ кунед: console.log, коди шарҳшуда.
  • Узр наовардед («натавонистам»). Беҳтараш: «ин нест, зеро… инак ман онро чӣ тавр илова мекардам».

Амал: тамрин

ВАЗИФАИ 10.1

Ҷавобҳоро ба саволҳои ҳимоя омода кунед

осон

Ба панҷ саволи боло дар бораи лоиҳаи худ бо суханони худатон, бо як-ду ҷумла ҷавоб диҳед. Ҷавобҳоро дар объект сабт кунед (инҳо ёддошт ҳастанд — санҷиши худкор нест), баъд назди ҳамсоя бо овози баланд такрор кунед. Вақте ҷавоб додед — вазифаро дастӣ қайд кунед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const defence = {
  ok: "Проверяю response.ok, потому что ...",
  states: "",
  debounce: "",
  race: "",
  ai: "",
};

console.log(Object.keys(defence).length + " ответов подготовлено");
Ишора 1

Мисли ба дӯсте ҷавоб диҳед, ки кодатонро ҳаргиз надидааст: кӯтоҳ ва бо мисол аз лоиҳа.

Ишора 2

Ҷавоби хуб мушаххас аст: «дар api.js, сатри 6, пас аз fetch if (!response.ok) меистад», на «хуб, дар он ҷо чизе месанҷад».

11 Кори назоратии №2 · версияи озмоишӣ

🚫 Дар кори назоратӣ ЗС хомӯш аст

Кори назоратии ҳақиқӣ — 30 дақиқа, бе ЗС, бе ишораҳо, бе чат ва бе ҳамсоя. Дар зер — версияи пурраи озмоишӣ: 10 вазифа оид ба мавзӯъҳои объектҳо, async/await, fetch, коркарди хатоҳо. Дар ин қисм ишораҳо нестанд (тугмаҳои «Ишора»-ро намебинед) — мисли кори назоратии ҳақиқӣ. Бо таймер барои 30 дақиқа ҳал кунед, аз саҳифа набароед ва чати ЗС-ро накушоед.

Версияи озмоишӣ чӣ тавр мегузарад

Ҳама ростқавлона: аввал таймерро мемонед, баъд ҳал мекунед. Ҳамаи «дархостҳо» дар ин ҷо — функсияҳои сохта аз Promise ва setTimeout ҳастанд, барои ҳамин ҷавоби ҳар вазифа худкор санҷида мешавад ва аз интернет вобаста нест. Тартиби сатрҳо дар консол низ ҷузъи натиҷа аст, пас ба он бодиққат нигоҳ кунед.

Нишондиҳанда барои худсанҷӣ: 9–10 вазифа — натиҷаи аъло, 7–8 — хуб, 5–6 — қаноатбахш, камтар аз 5 — дарсҳои 13–16-ро такрор кунед ва боз кӯшиш намоед. Ҳадди расмии кори назоратии ҳақиқиро муаллим муайян мекунад.

Кори назоратии №2 · 10 вазифа · 30 дақиқа

ВАЗИФАИ 11.1

Профили донишҷӯ (деструктуркунӣ)

осон

Барои ҳар донишҷӯ сатри Алишер (22) — Душанбе-ро чоп кунед. Агар шаҳр нест (address.city вуҷуд надорад) — не указан-ро чоп кунед. Деструктуркуниро истифода баред.

Таҳрир кардан мумкин аст · Ctrl + Enter
const students = [
  { name: "Алишер", age: 22, address: { city: "Душанбе" } },
  { name: "Мадина", age: 19, address: {} },
  { name: "Фаррух", age: 25, address: { city: "Худжанд" } },
];

// коди шумо
Натиҷаи интизоршаванда
Алишер (22) — Душанбе
Мадина (19) — не указан
Фаррух (25) — Худжанд
ВАЗИФАИ 11.2

Нархномаи чойхона (Object.entries)

осон

Объекти нархҳо дода шудааст. Маҷмӯи ҳамаи нархҳоро бо формати Сумма: 36 ва гаронтарин таомро бо формати Дороже всего: плов (25) чоп кунед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const prices = { плов: 25, чой: 5, самбуса: 6 };

// коди шумо
Натиҷаи интизоршаванда
Сумма: 36
Дороже всего: плов (25)
ВАЗИФАИ 11.3

Даромад аз рӯи шаҳрҳо (reduce ба объект)

миёна

Объекти «шаҳр → маҷмӯи фармоишҳо»-ро ҷамъ кунед ва тавассути JSON.stringify чоп намоед, баъд шумораи шаҳрҳоро бо формати Городов: 2.

Таҳрир кардан мумкин аст · Ctrl + Enter
const orders = [
  { city: "Душанбе", sum: 100 },
  { city: "Худжанд", sum: 80 },
  { city: "Душанбе", sum: 50 },
];

// коди шумо
Натиҷаи интизоршаванда
{"Душанбе":150,"Худжанд":80}
Городов: 2
ВАЗИФАИ 11.4

Хатогиро ёбед: await-и фаромӯшшуда

миёна

Баромади Привет, Алишер! ва Длина имени: 6 интизор аст. Ҳоло код чизи бемаъно чоп мекунад. Ислоҳ кунед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
const getName = () => wait(10).then(() => "Алишер");

async function greet() {
  const name = getName();
  console.log(`Привет, ${name}!`);
  return name.length;
}

greet().then((len) => console.log("Длина имени:", len));
Натиҷаи интизоршаванда
Привет, Алишер!
Длина имени: 6
ВАЗИФАИ 11.5

Ду дархости вобаста

миёна

async function showProfile(id)-ро нависед: аввал корбарро гиред (api.user(id)), баъд дастаи ӯро аз рӯи user.teamId (api.team(...)) ва Мадина — Frontend-17 (12 чел.)-ро чоп кунед. Пас аз анҷоми даъват готово чоп мешавад.

Таҳрир кардан мумкин аст · Ctrl + Enter
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
const api = {
  user: async (id) => { await wait(10); return { id, name: "Мадина", teamId: 7 }; },
  team: async (teamId) => { await wait(10); return { id: teamId, title: "Frontend-17", members: 12 }; },
};

// async function showProfile(id) { ... }

showProfile(1).then(() => console.log("готово"));
Натиҷаи интизоршаванда
Мадина — Frontend-17 (12 чел.)
готово
ВАЗИФАИ 11.6

Дархостҳои мувозӣ (Promise.all)

миёна

loadAll(ids)-ро нависед: ҳамаи шаҳрҳоро якбора дархост кунед ва массиви номҳоро бо тартиби ids (на бо тартиби омадани ҷавобҳо) баргардонед. Дархостҳои пай дар пай тартиби дигари сатрҳои пришёл …-ро медиҳанд ва санҷишро намегузаранд.

Таҳрир кардан мумкин аст · Ctrl + Enter
const delays = { 1: 30, 2: 5, 3: 15 };
const cities = { 1: "Душанбе", 2: "Худжанд", 3: "Бохтар" };
const getCity = (id) => new Promise((resolve) => setTimeout(() => {
  console.log("пришёл", id);
  resolve(cities[id]);
}, delays[id]));

// function loadAll(ids) { ... }

loadAll([1, 2, 3]).then((names) => console.log(names.join(", ")));
Натиҷаи интизоршаванда
пришёл 2
пришёл 3
пришёл 1
Душанбе, Худжанд, Бохтар
ВАЗИФАИ 11.7

getJson бо санҷиши ok

миёна

getJson(url)-ро бо ёрии fakeFetch нависед: агар response.ok дурӯғ бошад — хатоеро бо матни HTTP <статус> партоед, вагарна JSON-и таҳлилшударо баргардонед. Хатоҳо аз давраи поён бо коди аллакай омода коркард мешаванд.

Таҳрир кардан мумкин аст · Ctrl + Enter
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
const fakeFetch = async (url) => {
  await wait(5);
  if (url === "/users") return { ok: true, status: 200, json: async () => [{ name: "Алишер" }] };
  if (url === "/nope") return { ok: false, status: 404, json: async () => ({}) };
  return { ok: false, status: 500, json: async () => ({}) };
};

// async function getJson(url) { ... }

async function main() {
  for (const url of ["/users", "/nope", "/crash"]) {
    try {
      const data = await getJson(url);
      console.log("OK:", data.length);
    } catch (err) {
      console.log("Ошибка:", err.message);
    }
  }
}
main();
Натиҷаи интизоршаванда
OK: 1
Ошибка: HTTP 404
Ошибка: HTTP 500
ВАЗИФАИ 11.8

safeLoad: натиҷа ба ҷои истисно

душвор

safeLoad(task)-ро нависед: он функсияи ғайримуттаҳиди task-ро даъват мекунад ва { ok: true, data }-ро бармегардонад; ҳангоми хато — { ok: false, name: err.name, error: err.message }. Ҳисобкунаки finished бояд ҳангоми ҳар гуна анҷом афзояд (finally-ро истифода баред).

Таҳрир кардан мумкин аст · Ctrl + Enter
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
let finished = 0;

// async function safeLoad(task) { ... }

const tasks = [
  async () => { await wait(5); return [1, 2, 3]; },
  async () => { await wait(5); throw new Error("Сервер недоступен"); },
  async () => { await wait(5); throw new TypeError("Неверный формат"); },
];

async function main() {
  for (const task of tasks) {
    const result = await safeLoad(task);
    console.log(result.ok ? `данные: ${result.data.length}` : `${result.name}: ${result.error}`);
  }
  console.log("завершено:", finished);
}
main();
Натиҷаи интизоршаванда
данные: 3
Error: Сервер недоступен
TypeError: Неверный формат
завершено: 3
ВАЗИФАИ 11.9

retry: ҳангоми нокомӣ такрор мекунем

душвор

retry(fn, times)-ро нависед: то times кӯшиш fn-ро даъват мекунад; пеш аз ҳар яке Попытка N (аз як) чоп мекунад. Агар кӯшиш муваффақ шуд — натиҷаро бармегардонад. Агар ҳама нокомоданд — хатои кӯшиши охирин-ро мепартояд.

Таҳрир кардан мумкин аст · Ctrl + Enter
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
let attempt = 0;
const flaky = async () => {
  attempt++;
  await wait(5);
  if (attempt < 3) throw new Error(`сбой ${attempt}`);
  return "данные получены";
};
const alwaysBad = async () => { throw new Error("навсегда"); };

// async function retry(fn, times) { ... }

async function main() {
  console.log(await retry(flaky, 5));
  try {
    await retry(alwaysBad, 2);
  } catch (err) {
    console.log("Не вышло:", err.message);
  }
}
main();
Натиҷаи интизоршаванда
Попытка 1
Попытка 2
Попытка 3
данные получены
Попытка 1
Попытка 2
Не вышло: навсегда
ВАЗИФАИ 11.10

Ҳама якҷоя: load бо ҳолатҳо ва таймаут

душвор

load(api, onChange)-ро нависед. Аввал onChange("loading"). Баъд дархост бо таймаути 100 мс (withTimeout-и омода). Натиҷа: массиви ғайрихолӣ — onChange("success:N"), холӣ — onChange("empty"), ҳар гуна хато (аз ҷумла таймаут) — onChange("error:" + паём). Истисноҳо ба берун намеафтанд.

Таҳрир кардан мумкин аст · Ctrl + Enter
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
const withTimeout = (promise, ms) => Promise.race([
  promise,
  new Promise((_, reject) => setTimeout(() => reject(new Error("Таймаут")), ms)),
]);

const apis = {
  ok: async () => { await wait(10); return [1, 2, 3]; },
  empty: async () => { await wait(10); return []; },
  slow: async () => { await wait(300); return [1]; },
  bad: async () => { await wait(10); throw new Error("Сеть недоступна"); },
};

// async function load(api, onChange) { ... }

async function main() {
  for (const name of ["ok", "empty", "slow", "bad"]) {
    const log = [];
    await load(apis[name], (status) => log.push(status));
    console.log(name + ": " + log.join(" > "));
  }
}
main();
Натиҷаи интизоршаванда
ok: loading > success:3
empty: loading > empty
slow: loading > error:Таймаут
bad: loading > error:Сеть недоступна
Пас аз озмоишӣ

Қайд кунед, кадом вазифаҳо нашуданд, ва ба ду савол ҷавоб диҳед: «кадом дарсро бояд аз нав хонам?» ва «агар дар кори назоратии ҳақиқӣ ЗС фаъол мебуд, чӣ мекардам — ва барои чӣ ин ба фаҳмидани мавзӯъ кумак намекард?». Таҳлили хатоҳои маъмулро муаллим дар охири машғулот мегузаронад. Дар вазифаи хонагӣ шумо вазифаҳои ҳалнашударо аз нав менависед.

12 Таҳлил: ЗС дар куҷо вақтро сарфа кард ва дар куҷо аз роҳ бурд

Ин блоки ЗС-и дарс аст: пас аз ду лоиҳа муҳим аст, ки на танҳо «ЗС-ро истифода баред», балки қимати ҳақиқии онро донед. Аксар вақт ба назар мерасад, ки ЗС корро тезонд, баъд шумо як соат хатоиро дар коди бегона ва нофаҳмо меҷустед. Баръакс низ мешавад: ЗС дар се дақиқа он чизро шарҳ дод, ки шумо як шом сарф мекардед. Барои фарқ кардани якдигар на эҳсосот, балки сабтҳо лозиманд.

Қоидаҳои курс, ки ҳоло месанҷем

№1: аввал 15 дақиқа худам, баъд ЗС. №2: кодеро, ки сатр ба сатр фаҳмонида наметавонӣ, намегузорем. №5: ЗС нусхаи пешакӣ менависад — ту мантиқ, номҳо ва ҳолатҳои канориро месанҷӣ. Таҳлил нишон медиҳад, ки ин қоидаҳоро дар куҷо риоя кардед ва дар куҷо не.

Монандӣ аз ҳаёт

Навигатор дар мошин. Дар шоҳроҳи ношинос дар вилояти Суғд ӯ соатҳоро сарфа мекунад. Аммо агар кӯркӯрона ба ҳар ҷое ки ӯ мегӯяд равед, метавонед ба роҳи баста расед. Ронандаи хуб медонад, ки ба куҷо рафтан мехоҳад, ва ишораҳоро бо аломатҳо муқоиса мекунад. ЗС низ навигатор аст: ҳадаф ва санҷиш бар дӯши шумо мемонад.

Таҳлили сохторнок: қолаб

3–5 эпизод-ро аз лоиҳа интихоб кунед, ки дар он ба ЗС муроҷиат кардед. Барои ҳар кадом як сатри ҷадвалро пур кунед. Мисол (варианти Б, обуҳаво):

ЭпизодЧӣ пурсидамЧӣ гирифтамНатиҷа± дақиқаЧӣ тавр санҷидам
Нишонагузории кортаҳои обуҳаво«HTML ва CSS барои корта бисоз: шаҳр, ҳарорат, шамол»Нишонагузории корӣ, ду синфи зиёдатӣ✅ сарфа кард+25Дар браузер кушодам, зиёдатиро хориҷ кардам
Дархост ба API«Маълумоти current-и open-meteo-ро чӣ тавр гирифтан мумкин?»URL-и дуруст, аммо бе санҷиши ok⚖ қисман+15 / −10Ҳангоми санҷиш бо хатои 404 ёфтам
Коркарди хатоҳо«Тавре кун, ки наафтад»catch {}-и холӣ: хатоҳо хомӯшона фурӯ бурда мешуданд❌ аз роҳ бурд+5 / −40Дар реҷаи Offline пай бурдам: экран тағйир намеёфт

Ва акнун — қолаб барои README-и шумо. Онро нусха бардоред ва бо эпизодҳои худатон пур кунед:

Қолаби таҳлил — ба README.md гузоред
## ИИ в проекте: где помог, где увёл в сторону

### Эпизод 1: <что делал>
- Что просил (коротко): …
- Что получил: …
- Итог: ✅ сэкономил / ⚖ частично / ❌ увёл в сторону
- Минуты: сэкономил … / потерял …
- Как проверил результат: …
- Вывод для себя (правило): …

### Эпизод 2: …

## Итог
- Где ИИ реально сэкономил время: …
- Где он увёл в сторону и почему я не заметил сразу: …
- Что я теперь делаю иначе: …

Се савол барои худсанҷӣ

  1. Оё ман ин кодро сатр ба сатр шарҳ дода метавонам? Агар не — ин қарз аст: шумо чизи бегонаро гирифтед ва нафаҳмидед. Ё таҳлил кунед, ё аз нав бинависед.
  2. Аз куҷо фаҳмидам, ки ҷавоби ЗС дуруст аст? «Кор кард» — санҷиши суст. Хуб: ба таври қасдӣ вайрон кардам (Offline, 404, дархости холӣ) ва боварӣ ҳосил намудам, ки рафтор бомаъност.
  3. Бе ЗС чӣ мекардам — ва ин чӣ қадар арзиш дошт? Баҳои ростқавлона кумак мекунад, ки бифаҳмем, фоида дар куҷо воқеӣ аст ва дар куҷо — худфиребӣ.

«Аз роҳ бурданҳои» маъмул дар лоиҳаҳо бо API

ЗС чиро бад мекунад

  • response.ok-ро фаромӯш мекунад — 404 ҳамчун маълумот «бо муваффақият» нишон дода мешавад
  • catch-и холӣ ё танҳо console.log менависад ба ҷои паём ба корбар
  • Дар бораи рақобати ҷавобҳо ва дархости дукарата фикр намекунад
  • Майдонҳои вуҷуднадоштаи API-ро меандешад (data.weather.temp) — онҳоро бо ҷавоби ҳақиқӣ муқоиса кардан лозим аст
  • Зиёдатиро пешниҳод мекунад: китобхонаҳо, фреймворкҳо, чорчӯбаи мураккаби try/catch

ЗС дар куҷо воқеан кумак мекунад

  • Тақсими лоиҳа ба қадамҳо (қисми 04)
  • Шарҳи паёми нофаҳмои хато — бо коди шумо ва матни хато
  • Нусхаи пешакии нишонагузорӣ ва CSS, ки шумо баъд мехонед ва ислоҳ мекунед
  • Ревью аз рӯи чек-лист — пас аз одамон
  • README ва матнҳо — бо ислоҳи ҳатмӣ бо суханони худатон
кодамро баҳо деҳ
Контекст: лоиҳаи таълимии «ҷустуҷӯи маҳсулот», JS + Vite, модулҳои api.js / ui.js / main.js. Медонам: fetch, async/await, try/catch, debounce. Вазифа: ревьюи файли api.js-ро анҷом деҳ — танҳо мулоҳизаҳо, бе аз нав навиштани код. Маҳдудиятҳо: ба 4 чиз нигоҳ кун: санҷиши response.ok, коркарди хатоҳо, номҳо, такрор. Формати ҷавоб: рӯйхати «сатр → мушкил → чаро муҳим аст → чӣ тавр ислоҳро санҷидан». Санҷиш: дар охир як ҷойро номбар кун, ки боварӣ надорӣ, ки ман API-ро дуруст фаҳмидам. [коди api.js-ро гузоред]

Муфассалтар хонед: MDN — ислоҳи хатои JavaScript

Амал: қимати ЗС-ро ҳисоб мекунем

ВАЗИФАИ 12.1

Хулосаҳои таҳлили эпизодҳо

миёна

Эпизодҳои таҳлил дар массив ҳастанд. Барои ҳар кадом нишон дода шудааст, ки ЗС чанд дақиқа сарфа кард (saved) ва чанд дақиқа гум кард (lost: ҷустуҷӯи хато дар коди бегона, аз нав навиштан). Маҷмӯъҳо ва натиҷаи бо аломатро (+20 ё -5) ҳисоб кунед ва эпизоди бо зиёнии калонтаринро ёбед. Чор сатрро аз рӯи намунаи зер чоп кунед.

Таҳрир кардан мумкин аст · Ctrl + Enter
const episodes = [
  { task: "разметка карточек", saved: 25, lost: 0 },
  { task: "запрос к API", saved: 15, lost: 10 },
  { task: "debounce", saved: 10, lost: 0 },
  { task: "обработка ошибок", saved: 5, lost: 40 },
  { task: "README", saved: 15, lost: 0 },
];

// ҳисоб кунед ва чор сатрро чоп намоед
Натиҷаи интизоршаванда
Сэкономил: 70 мин
Потерял: 50 мин
Итого: +20 мин
Главная ловушка: обработка ошибок
Ишора 1

Ду маҷмӯъро ду reduce (ё як давра) ҷамъ мекунад. Натиҷа — фарқи saved − lost.

Ишора 2

Аломат: net > 0 ? "+" + net : String(net). Эпизоди бадтарин — reduce, ки унсурро бо lost-и калонтар мемонад.

13 Вазифаи хонагӣ

Лоиҳаро аз рӯи мулоҳизаҳои ревью ва ҳимоя такмил диҳед, таҳлили «ЗС дар лоиҳа»-ро ороиш диҳед ва оид ба кори назоратӣ кор бар хатоҳо кунед.

Чӣ кор кардан лозим

  • ☐ Мулоҳизаҳои ревью ва ҳимояро, ки қабул кардед, ислоҳ кунед.
  • ☐ Ҳамаи бандҳои MVP-ро аз қисми 02 санҷед ва чек-листи ревьюерро аз рӯи лоиҳаи худ боз як бор гузаред; npm run build бе хато.
  • ☐ console.log-ҳои зиёдатӣ, коди шарҳшуда ва функсияҳои мурдаро хориҷ кунед.
  • ☐ Ба README бахши «ЗС дар лоиҳа»-ро аз рӯи қолаби қисми 12 илова кунед (3–5 эпизод ва хулоса — бо суханони худатон).
  • ☐ Репозиторийро навсозӣ кунед: оммавӣ, README бо скриншот, на камтар аз 5 commit-и бомаъно, node_modules ва dist бор нашудаанд.
  • ☐ Кор бар хатоҳо: ҳар вазифаи кори назоратии озмоиширо, ки ҳал накардед ё бо хато ҳал кардед, аз нав ҳал кунед ва бо суханони худатон шарҳ диҳед, ки хато дар чӣ буд (1–2 ҷумла дар шарҳ).

Чӣ супоридан лозим

Истиноди репозиторийро ба чати гурӯҳ (Telegram) фиристед. Дар паём нависед: варианти лоиҳа (А, Б ё В), кадом API-ро истифода кардед, пас аз ревью чӣ илова кардед, кадом бонус сохтед, ва рӯйхати вазифаҳои кори назоратӣ, ки аз нав кардед.

Вазифаи хонагӣ чӣ тавр баҳо дода мешавад (0–10)

Чиро месанҷемХолҳо
Истинод бе вуруд кушода мешавад, npm run build дар нусхаи тоза мегузарад2
Мулоҳизаҳои ревью ислоҳ шудаанд (дар commit-ҳо намоён аст)2
README: тавсиф, скриншот ва бахши «ЗС дар лоиҳа» бо суханони худатон3
На камтар аз 5 commit-и бомаъно бо паёмҳои фаҳмо1
Кор бар хатоҳо оид ба кори назоратӣ бо шарҳҳо2

Ин баҳо барои вазифаи хонагии дарс аст (0–10). Баҳо барои лоиҳаи хурд (0–100) аз рӯи ҷадвали қисми 03 гузошта мешавад ва алоҳида ҳисоб карда мешавад.

✓ Варақаи кӯмакии дарс

  • Лоиҳа: барнома дар API-и оммавӣ (маҳсулот, обуҳаво ё корбарон) дар Vite. Баҳо 0–100: MVP 20, fetch ва async/await 20, ҳолатҳо 15, debounce ва назорати дархостҳо 10, модулҳо 10, ҷамъбаст ва репозиторий 5, интерфейс 5, ҳимоя 15; бонус то +5.
  • fetch: await fetch(url) → if (!response.ok) throw … → await response.json(). fetch танҳо ҳангоми нокомии шабака меафтад, 404 ва 500 — ҷавобҳои «муваффақ».
  • Ҳолатҳо: як объекти { status, items, error }, status: idle / loading / success / error; success-и холӣ — ин empty аст. Иваз шудани статус майдонҳои зиёдатиро тоза мекунад.
  • try/catch/finally: catch ба корбар паёми фаҳмо нишон медиҳад, на хомӯш мемонад; finally ҳамеша иҷро мешавад.
  • Мувозӣ ё пай дар пай: дархостҳои мустақил — Promise.all, вобастаҳо — await пай дар пай. Promise.race — барои таймаут.
  • debounce: таймерро ҳангоми ҳар даъват аз сифр мекунем; пас аз таваққуф кор мекунад. Дархости холиро ба сервер намефиристем.
  • Рақобати ҷавобҳо: рақами дархост (myId !== latestId → нодида) ё AbortController.
  • Модулҳо: api.js — шабака, ui.js — DOM, main.js — пайвандак; пеш аз ҳимоя npm run build + preview; dist ва node_modules дар Git нестанд.
  • Ревью: иҷро (Offline, Slow 3G, партов) → хондан аз рӯи чек-лист → мулоҳиза = дар куҷо, чӣ мебинам, чаро, пешниҳод.
  • Кори назоратии №2: 30 дақиқа, бе ЗС, мавзӯъҳо — объектҳо, async/await, fetch, хатоҳо; 10 вазифа бо санҷиши худкор.
  • ЗС дар лоиҳа: эпизодҳоро сабт кунед (чӣ пурсидам → чӣ гирифтам → натиҷа → ± дақиқа → чӣ тавр санҷидам). ЗС аксар вақт ok-ро фаромӯш мекунад, хатоҳоро фурӯ мебарад ва майдонҳои API-ро меандешад — санҷиш бар дӯши шумо мемонад.