JavaScript Asynchronous Programming: Promises, async/await & Fetch API (మాస్టర్ గైడ్)
జావాస్క్రిప్ట్ అనేది సహజంగా Single-threaded లాంగ్వేజ్ — అంటే కంప్యూటర్లో ఒకే ఒక్క వర్కర్ ఉన్నట్లు. మరి సర్వర్ నుండి 10,000 యూజర్ల డేటా రావడానికి 3 సెకన్లు పడితే, ఆ 3 సెకన్ల పాటు బ్రౌజర్ స్క్రీన్ ఫ్రీజ్ అయిపోతే యూజర్ ఎంత చిరాకు పడతాడు? స్క్రీన్ ఆగకుండా బ్యాక్గ్రౌండ్లో పనులు చేసే అద్భుతమే Asynchronous JavaScript.
పిజ్జా రెస్టారెంట్ బజర్ టోకెన్ అనాలజీ (Restaurant Buzzer Token Analogy):
1. Synchronous (సింగిల్ విండో బ్యాంక్ క్యూ): ఒకరి పని పూర్తయ్యే వరకు వెనక ఉన్న 100 మంది లైన్ లో కదలకుండా నిలబడాలి.
2. Asynchronous (ఎలక్ట్రానిక్ బజర్ టోకెన్ / Promise): మీరు పిజ్జా ఆర్డర్ ఇవ్వగానే, వంటవాడు పిజ్జా చేసేవరకు మీరు కౌంటర్ ముందే నిలబడరు! మీ చేతిలో ఒక ఎలక్ట్రానిక్ బజర్ టోకెన్ పెడతారు. మీరు హాయిగా కుర్చీలో కూర్చుని ఫోన్ చూసుకోవచ్చు (Non-blocking UI).
పిజ్జా సిద్ధం కాగానే బజర్ మోగుతుంది (Resolved / Success). పిజ్జా పిండి అయిపోతే ఎరుపు లైట్ వెలుగుతుంది (Rejected / Error).
ఈ పాఠంలో మనం పాత కాలపు Callback Hell నుండి విముక్తి పొంది, ES6 Promises మరియు అత్యంత ఆధునికమైన async / await తో పాటు, లైవ్ ఇంటర్నెట్ నుండి సర్వర్ API డేటాను తెచ్చే fetch() ని సంక్షిప్తమైన ప్రొడక్షన్ కోడ్తో నేర్చుకుందాం.
జావాస్క్రిప్ట్ ఇంజిన్ లో Event Loop అనే ఒక అద్భుతమైన ట్రాఫిక్ పోలీస్ ఉంటాడు:
🚦 Event Loop ట్రాఫిక్ పోలీస్ సిద్ధాంతం:
జావాస్క్రిప్ట్ ప్రధాన థ్రెడ్ (Call Stack) ఎల్లప్పుడూ బటన్ క్లిక్స్, యానిమేషన్స్ వంటి తక్షణ పనులను క్షణాల్లో పూర్తి చేస్తుంది.
ఏదైనా సర్వర్ నెట్వర్క్ రిక్వెస్ట్ లేదా టైమర్ (setTimeout) వచ్చినప్పుడు — దానిని పక్కనున్న Web APIs కి అప్పగించి, ప్రధాన రోడ్డును ఖాళీగా ఉంచుతుంది. డేటా రాగానే మైక్రోటాస్క్ క్యూ ద్వారా ఫలితాన్ని తీసుకుంటుంది. అందుకే వెనుక నెట్వర్క్ కాల్స్ నడుస్తున్నా మీ వెబ్సైట్ స్క్రోలింగ్ స్మూత్గా సాగుతుంది!
అసింక్రోనస్ కోడ్ రాయడంలో జావాస్క్రిప్ట్ ప్రయాణించిన 3 తరాలు:
| దశ | పద్ధతి | లోపం లేదా ప్రయోజనం |
|---|---|---|
| తరం 1 (పాతది) | Callbacks (ఫంక్షన్ లోపల ఫంక్షన్) | 🚨 Callback Hell: కోడ్ కుడివైపుకు పిరమిడ్ లా జరిగిపోయి చదవడం అసాధ్యంగా మారేది. |
| తరం 2 (ES6) | Promises (.then(), .catch()) |
చైనింగ్ ద్వారా చదవడం సులభమైంది, కానీ ఇప్పటికీ బ్రాకెట్లు ఎక్కువగా ఉండేవి. |
| తరం 3 (ఆధునిక ప్రామాణికం) | async / await |
✅ ఇండస్ట్రీ స్వర్గం: బ్యాక్గ్రౌండ్లో ప్రామిసే నడుస్తుంది, కానీ కోడ్ చూడటానికి సాధారణ సింక్రోనస్ కోడ్ లాగే క్రిస్టల్ క్లియర్గా ఉంటుంది! |
ప్రతి Promise తన జీవిత కాలంలో 3 స్థితులలో ఏదో ఒకదానిలో ఉంటుంది:
⏳ Promise లైఫ్సైకిల్:
1. Pending (వేచి ఉండటం): రిక్వెస్ట్ పంపబడింది, ఫలితం ఇంకా రాలేదు (టోకెన్ బజర్ నిశ్శబ్దంగా ఉంది).
2. Fulfilled / Resolved (విజయం): పని విజయవంతమై డేటా చేతికి వచ్చింది. (బజర్ మోగింది ➔ await ద్వారా డేటా దొరుకుతుంది).
3. Rejected (వైఫల్యం): నెట్వర్క్ ఎర్రర్ లేదా సర్వర్ డౌన్ అయింది. (ఎరుపు లైట్ ➔ catch బ్లాక్ లోకి వెళుతుంది).
ఆధునిక బ్రౌజర్లలో సర్వర్ నుండి డేటా తేవడానికి fetch() వాడతాం. ఇక్కడ బిగినర్స్ చేసే అతిపెద్ద తప్పు — ఒకే ఒక్క await పెట్టడం!
🔑 ఎందుకు రెండుసార్లు await వాడాలి?
• స్టెప్ 1: const res = await fetch(url);
సర్వర్ తో కనెక్షన్ ఏర్పడి HTTP హెడర్స్ (Status Code: 200, 404) మాత్రమే వచ్చాయి. ఇంకా పూర్తి డేటా బాడీ రాలేదు!
• స్టెప్ 2: const data = await res.json();
ఇప్పుడు నెట్వర్క్ స్ట్రీమ్ నుండి వచ్చిన సమాచారాన్ని చదివి జావాస్క్రిప్ట్ ఆబ్జెక్ట్గా మార్చడానికి రెండోసారి await తప్పనిసరి!
ఒక నెట్వర్క్ ఆలస్యాన్ని (Delay) అనుకరిస్తూ, ప్రామిస్ను సృష్టించి ఆధునిక async/await మరియు try...catch తో హ్యాండిల్ చేసే కేవలం 14 లైన్ల సంక్షిప్త కోడ్:
// 1. ప్రామిస్ ఉత్పత్తి చేసే ఫంక్షన్ (నెట్వర్క్ ఆలస్యం సిమ్యులేషన్)
const orderFood = (item) => new Promise((resolve, reject) => {
setTimeout(() => (item ? resolve(item + " సిద్ధమైంది! 🍔") : reject("ఆర్డర్ రద్దు ❌")), 50);
});
// 2. ఆధునిక async/await వినియోగం
async function serveCustomer() {
try {
const food = await orderFood("చీజ్ బర్గర్");
console.log("సర్వర్ డెలివరీ:", food);
} catch (err) {
console.error("లోపం సంభవించింది:", err);
}
}
serveCustomer();
సర్వర్ డెలివరీ: చీజ్ బర్గర్ సిద్ధమైంది! 🍔
await orderFood(...)పిజ్జా బజర్ టోకెన్ మోగే వరకు మాత్రమే వేచి ఉండి, ఫలితాన్ని నేరుగా వేరియబుల్కు అందించింది.- ఏదైనా లోపం జరిగితే వెంటనే
catchబ్లాక్ రక్షణ కవచంలా అడ్డుకుని యాప్ క్రాష్ కాకుండా కాపాడింది.
ప్రొడక్షన్ అప్లికేషన్లలో డెవలపర్లను ముంచేసే ప్రధాన సమస్యలు:
ఇది జావాస్క్రిప్ట్ లోని అత్యంత భయంకరమైన చిక్కు! సర్వర్ 404 Not Found లేదా 500 Server Error ఇచ్చినా కూడా fetch() విజయవంతంగా రిసాల్వ్ అయిపోతుంది! కేవలం ఇంటర్నెట్ డిస్కనెక్ట్ అయితేనే క్యాచ్ అవుతుంది.
పరిష్కారం: ఎల్లప్పుడూ if (!res.ok) throw new Error(res.status) అని తనిఖీ చేయాలి.
const data = res.json(); // ❌ Promise { <pending> } మాత్రమే వస్తుంది!
ఖచ్చితంగా const data = await res.json(); అని రాయాలి.
await కీవర్డ్ సాధారణ ఫంక్షన్ లోపల పనిచేయదు; కేవలం async function లోపల మాత్రమే పనిచేస్తుంది.
రెండు సంబంధం లేని APIs ఉన్నప్పుడు await api1(); await api2(); రాస్తే రెట్టింపు సమయం పడుతుంది. రెండింటినీ ఒకేసారి పారలల్గా రన్ చేయడానికి Promise.all([api1(), api2()]) వాడాలి!
సర్వర్ డౌన్ అయినప్పుడు యాప్ తెల్ల స్క్రీన్ లాగా ఆగిపోకుండా ఉండాలంటే ఎల్లప్పుడూ try...catch తప్పనిసరి.
నిజమైన సర్వర్ నుండి లైవ్ యూజర్ వివరాలను సేకరించి, ఎర్రర్ వస్తే సురక్షితమైన ఫాల్బ్యాక్ అందించే ప్రొడక్షన్-గ్రేడ్ API ఫంక్షన్ (కేవలం 13 లైన్లలో):
ఈ కోడ్ను కంపైలర్ లో రన్ చేసి లైవ్ సర్వర్ రెస్పాన్స్ను తనిఖీ చేయండి:
// లైవ్ సర్వర్ నుండి యూజర్ డేటా తెచ్చే కాంపాక్ట్ ఫంక్షన్
async function fetchUserProfile(userId) {
try {
const res = await fetch("https://jsonplaceholder.typicode.com/users/" + userId);
if (!res.ok) throw new Error("సర్వర్ లోపం: " + res.status);
const user = await res.json();
return { name: user.name, email: user.email, company: user.company.name };
} catch (error) {
return { error: true, message: error.message };
}
}
// యూజర్ ఐడీ 1 కోసం లైవ్ రిక్వెస్ట్
fetchUserProfile(1).then((data) => {
console.log("యూజర్ పేరు:", data.name);
console.log("ఈమెయిల్:", data.email);
console.log("కంపెనీ:", data.company);
});
యూజర్ పేరు: Leanne Graham
ఈమెయిల్: Sincere@april.biz
కంపెనీ: Romaguera-Crona
ఈ క్రింది ప్రశ్నలకు స్వయంగా ఆలోచించి, డ్రాప్డౌన్ తెరిచి మీ అవగాహనను సరిచూసుకోండి:
- జావాస్క్రిప్ట్ సింగిల్ థ్రెడ్ అయినప్పటికీ బ్రౌజర్ ఎందుకు ఫ్రీజ్ అవ్వదు?
- ఒక Promise లోని 3 స్థితులు ఏమిటి?
- సర్వర్ 404 Not Found కోడ్ ఇచ్చినప్పుడు
fetch()క్యాచ్ బ్లాక్లోకి ఎందుకు వెళ్లదు? - రెండు స్వతంత్ర API రిక్వెస్టులను పారలల్గా ఒకేసారి రన్ చేయడానికి ఏ పద్ధతి వాడతారు?
fetch()తో డేటా తెచ్చేటప్పుడు రెండుసార్లుawaitఎందుకు వాడాలి?- Callbacks తో పోలిస్తే
async/awaitయొక్క అతిపెద్ద ప్రయోజనం ఏమిటి?
👉 సమాధానాలు మరియు వివరణలు చూడండి (Click to Expand)
1. సమాధానం: Event Loop & Web APIs ద్వారా. టైమర్లు, నెట్వర్క్ పనులను బ్రౌజర్ బ్యాక్గ్రౌండ్ థ్రెడ్స్కి అప్పగించి ప్రధాన కాల్ స్టాక్ను ఫ్రీగా ఉంచుతుంది.
2. సమాధానం: Pending (వేచి ఉండటం), Fulfilled (విజయవంతమైంది), Rejected (విఫలమైంది).
3. సమాధానం: fetch() దృష్టిలో సర్వర్ నుండి ఏదో ఒక రెస్పాన్స్ (404 అయినా) వచ్చింది కాబట్టి HTTP కమ్యూనికేషన్ విజయవంతమైనట్లే. కేవలం ఇంటర్నెట్ లేకపోతేనే క్యాచ్ అవుతుంది. కాబట్టి res.ok ని మ్యానువల్గా చెక్ చేయాలి.
4. సమాధానం: Promise.all([fetch1, fetch2]).
5. సమాధానం: మొదటి await నెట్వర్క్ హెడర్స్ కోసం, రెండో await బాడీలోని స్ట్రీమ్ డేటాను JSON ఆబ్జెక్ట్గా మార్చడం కోసం.
6. సమాధానం: Callback Hell నివారణ మరియు సాధారణ సింక్రోనస్ కోడ్ లాగే try...catch తో సులభంగా ఎర్రర్ హ్యాండ్లింగ్ చేయగలగడం.
📌 సారాంశం (Quick Summary):
- Async స్వభావం: నెట్వర్క్ పనుల వల్ల UI ఆగకుండా బ్యాక్గ్రౌండ్లో పనులు నడవడం.
- Promise: భవిష్యత్తులో అందబోయే ఫలితానికి హామీ ఇచ్చే బజర్ టోకెన్.
- async/await: ప్రామిస్లను అత్యంత శుభ్రంగా హ్యాండిల్ చేసే ఆధునిక విధానం.
- Fetch API: ఎల్లప్పుడూ
res.okతనిఖీ చేయాలి మరియుawait res.json()వాడాలి. - భద్రత: ప్రతి అసింక్ కాల్ చుట్టూ
try...catchఉండటం తప్పనిసరి.
🏁 గ్రాండ్ ఫినాలే: చివరి 25వ అధ్యాయం →
మనం జావాస్క్రిప్ట్ మాస్టర్క్లాస్ ఆఖరి మజిలీకి చేరుకున్నాం!
చివరి పాఠంలో బ్రౌజర్ రీఫ్రెష్ చేసినా డేటా శాశ్వతంగా ఉండే localStorage API మరియు ప్రొడక్షన్ లో యాప్ క్రాష్ అవ్వకుండా కాపాడే Error Handling (try, catch, finally, throw) గురించి వివరంగా నేర్చుకుని ఈ కోర్సును విజయవంతంగా పూర్తి చేసుకుందాం!