4.5 פרומיסים ו async await תרגול
תרגול - פרומיסים ו-async/await¶
תרגיל 1 - פרומיסים בסיסיים¶
חלק א¶
כתבו פונקציה delay(ms) שמחזירה Promise שמתקיים אחרי ms מילישניות:
חלק ב¶
כתבו פונקציה randomSuccess(chance) שמחזירה Promise שמצליח בהסתברות של chance (מספר בין 0 ל-1) ונכשל אחרת. ה-Promise מתקיים אחרי שניה:
randomSuccess(0.7)
.then(() => console.log("Success!"))
.catch(() => console.log("Failed!"));
// 70% chance of "Success!", 30% chance of "Failed!"
תרגיל 2 - שרשור Promises¶
כתבו סימולציה של API שמחזיר נתונים עם השהייה. ממשו שלוש פונקציות:
fetchUser(id)- מחזירה Promise עם אובייקט{ id, name, departmentId }אחרי 500msfetchDepartment(id)- מחזירה Promise עם{ id, name, managerId }אחרי 500msfetchManager(id)- מחזירה Promise עם{ id, name, email }אחרי 500ms
כתבו פונקציה getUserManagerEmail(userId) ששולפת את האימייל של המנהל של המחלקה של המשתמש:
// using promise chaining:
getUserManagerEmail(1).then(email => console.log(email));
// using async/await:
const email = await getUserManagerEmail(1);
כתבו את הפונקציה בשתי גרסאות: אחת עם שרשור then ואחת עם async/await.
תרגיל 3 - Promise.all לעומת ריצה סדרתית¶
נתונות שלוש פונקציות שכל אחת לוקחת שניה:
function fetchUsers() {
return new Promise(resolve =>
setTimeout(() => resolve(["Alice", "Bob"]), 1000)
);
}
function fetchPosts() {
return new Promise(resolve =>
setTimeout(() => resolve(["Post 1", "Post 2"]), 1000)
);
}
function fetchComments() {
return new Promise(resolve =>
setTimeout(() => resolve(["Comment 1"]), 1000)
);
}
חלק א¶
כתבו פונקציה loadAllSequential() שטוענת את שלושתם סדרתית (אחד אחרי השני). מדדו כמה זמן לוקח.
חלק ב¶
כתבו פונקציה loadAllParallel() שטוענת את שלושתם במקביל. מדדו כמה זמן לוקח.
השתמשו ב-console.time ו-console.timeEnd למדידה:
console.time("sequential");
const data = await loadAllSequential();
console.timeEnd("sequential"); // ~3 seconds
console.time("parallel");
const data2 = await loadAllParallel();
console.timeEnd("parallel"); // ~1 second
תרגיל 4 - טיפול בשגיאות¶
כתבו פונקציה safeFetch(url) שעוטפת fetch עם הטיפולים הבאים:
- אם ה-response לא ok (סטטוס לא 200-299), זורקת שגיאה עם הסטטוס
- אם יש שגיאת רשת, תופסת אותה ומחזירה אובייקט שגיאה
- מדפיסה "Done" בכל מקרה (הצלחה או כישלון)
async function safeFetch(url) {
// your code here
}
// returns { ok: true, data: {...} } on success
// returns { ok: false, error: "..." } on failure
בנוסף, כתבו פונקציה fetchMultiple(urls) שמקבלת מערך URLs ומחזירה את התוצאות של כולם (גם אם חלקם נכשלים). השתמשו ב-Promise.allSettled.
תרגיל 5 - retry עם backoff¶
כתבו פונקציה retryAsync(fn, maxRetries, initialDelay) שמנסה להריץ פונקציה אסינכרונית עד שהיא מצליחה:
fn- פונקציה אסינכרונית להרצהmaxRetries- מספר ניסיונות מקסימלי (ברירת מחדל 3)initialDelay- השהייה לפני ניסיון חוזר ראשון במילישניות (ברירת מחדל 1000)- ההשהייה מוכפלת בכל ניסיון (exponential backoff): 1000ms, 2000ms, 4000ms...
- מדפיסה את מספר הניסיון בכל פעם
- אם כל הניסיונות נכשלו, זורקת את השגיאה האחרונה
let callCount = 0;
async function unreliableApi() {
callCount++;
if (callCount < 3) {
throw new Error("Server error");
}
return { data: "success" };
}
const result = await retryAsync(unreliableApi);
// Attempt 1 failed: Server error (retrying in 1000ms)
// Attempt 2 failed: Server error (retrying in 2000ms)
// Attempt 3 succeeded!
console.log(result); // { data: "success" }
תרגיל 6 - Promise.race - timeout¶
חלק א¶
כתבו פונקציה withTimeout(promise, ms) שמקבלת Promise וזמן מקסימלי. אם ה-Promise לא מסתיים בזמן, מחזירה שגיאת timeout:
const fast = delay(500).then(() => "fast result");
const slow = delay(5000).then(() => "slow result");
console.log(await withTimeout(fast, 1000)); // "fast result"
console.log(await withTimeout(slow, 1000)); // throws Error: "Timeout after 1000ms"
חלק ב¶
כתבו פונקציה fetchFastest(urls) שמקבלת מערך URLs ומחזירה את התוצאה של הבקשה הראשונה שמצליחה (השתמשו ב-Promise.any):
const result = await fetchFastest([
"https://slow-api.com/data",
"https://fast-api.com/data",
"https://medium-api.com/data"
]);
// returns response from whichever is fastest
תרגיל 7 - עיבוד תור משימות¶
כתבו מחלקה AsyncQueue שמעבדת משימות אסינכרוניות בתור:
enqueue(asyncFn)- מוסיפה משימה לתור ומחזירה Promise שיתקיים כשהמשימה תסתייםgetQueueSize()- מחזיר כמה משימות ממתינותisProcessing()- מחזיר אם יש משימה שרצה כרגע
המשימות רצות אחת אחרי השנייה (לא במקביל). כל משימה מתחילה רק אחרי שהקודמת סיימה.
const queue = new AsyncQueue();
// these should run sequentially, not in parallel
queue.enqueue(async () => {
await delay(1000);
console.log("Task 1 done");
return "result 1";
});
queue.enqueue(async () => {
await delay(500);
console.log("Task 2 done");
return "result 2";
});
const result3 = await queue.enqueue(async () => {
await delay(200);
console.log("Task 3 done");
return "result 3";
});
// Output (in order):
// "Task 1 done" (after 1 second)
// "Task 2 done" (after 1.5 seconds)
// "Task 3 done" (after 1.7 seconds)
console.log(result3); // "result 3"
בונוס: הוסיפו פרמטר concurrency ל-constructor שמגדיר כמה משימות יכולות לרוץ במקביל.