פרק 14: Async and Await ב-JavaScript

1. מה זה async ו-await?

async ו-await הם תכונות חדשות יחסית ב-JavaScript (שהוצגו ב-ES2017), שמאפשרות עבודה עם קוד אסינכרוני בצורה נוחה, קריאה ומסודרת יותר מאשר עם Promises בלבד. במקום לשרשר פעולות עם then ו-catch, ניתן לכתוב קוד אסינכרוני בסגנון של קוד סינכרוני, וזה מקל מאוד על קריאת הקוד והבנתו.

  • async: משמש להגדיר פונקציה כ"אסינכרונית". פונקציה שמוגדרת כ-async תחזיר תמיד Promise, אפילו אם מחזירים ערך רגיל.
  • await: משמש בתוך פונקציה אסינכרונית להמתנה ל-Promise שיתקיים. בזמן ההמתנה, הקוד לא ממשיך להתבצע (מבחינת אותה הפונקציה), אך התוכנית כולה ממשיכה לעבוד.

2. התחביר הבסיסי של async ו-await

התחביר הבסיסי של פונקציה אסינכרונית משתמש במילת המפתח async לפני ההגדרה של הפונקציה, ומילת המפתח await משמשת כדי להמתין לפתרון של Promise בתוך הפונקציה.

דוגמה בסיסית:

async function fetchData() {
    let data = await fetch('https://jsonplaceholder.typicode.com/posts/1');
    let json = await data.json(); // המתנה להמרת התגובה לפורמט JSON
    console.log(json);
}

fetchData();

הסבר:

  • הפונקציה fetchData הוגדרה עם async, ולכן ניתן להשתמש ב-await בתוכה.
  • await מאפשר להמתין ל-Promise שיתקיים לפני שהקוד ממשיך.
  • הפונקציה fetch() היא אסינכרונית ומחזירה Promise, אז אנחנו משתמשים ב-await כדי להמתין שהבקשה תסתיים ונוכל לעבד את התוצאה.

3. יצירת פונקציה עם async

כדי להשתמש ב-await, חייבים להגדיר את הפונקציה עם מילת המפתח async. זה הופך את הפונקציה לאסינכרונית ומאפשר לה להחזיר Promise אוטומטית.

דוגמה:

async function greet() {
    return "Hello!";
}

greet().then(result => console.log(result)); // מציג "Hello!"

הסבר:

  • הפונקציה greet מוגדרת כ-async, ולכן היא מחזירה Promise שמתקיים אוטומטית ומחזיר את הערך "Hello!".
  • השימוש ב-then מאפשר לנו לקבל את התוצאה ולהדפיס אותה.

4. שימוש ב-await

מילת המפתח await עוצרת את ביצוע הפונקציה עד ש-Promise מסוים מתקיים ומחזיר תוצאה. היא יכולה לשמש רק בתוך פונקציה שמוגדרת כ-async.

דוגמה לשימוש ב-await:

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function displayMessage() {
    console.log("Wait for 2 seconds...");
    await delay(2000); // המתנה של 2 שניות
    console.log("2 seconds passed!");
}

displayMessage();

הסבר:

  • הפונקציה delay מחזירה Promise שמתממש אחרי מספר מילישניות שניתן לה כפרמטר (במקרה הזה, 2000 מילישניות = 2 שניות).
  • בתוך הפונקציה האסינכרונית displayMessage, אנחנו משתמשים ב-await כדי להמתין שההמתנה תסתיים לפני שהקוד ממשיך.
  • הפלט יהיה:
Wait for 2 seconds...
2 seconds passed!

5. טיפול בשגיאות עם try...catch

כאשר משתמשים ב-async ו-await, ניתן לטפל בשגיאות בצורה מסודרת בעזרת בלוק try...catch. זה מאפשר לנהל שגיאות בתוך פונקציות אסינכרוניות באופן נקי יותר מאשר עם catch של Promises.

דוגמה לשימוש ב-try...catch:

async function fetchData() {
    try {
        let response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
        if (!response.ok) {
            throw new Error('Network response was not ok');
        }
        let data = await response.json();
        console.log(data);
    } catch (error) {
        console.log("Error:", error.message);
    }
}

fetchData();

הסבר:

  • עטפנו את הקוד האסינכרוני בבלוק try כדי לנסות להפעיל אותו.
  • אם מתרחשת שגיאה (כמו בעיה ברשת), הקוד בבלוק catch יתפוס את השגיאה ויטפל בה.
  • אם הבקשה לרשת לא מצליחה או מתקבלת תשובה לא תקינה, נזרוק שגיאה עם throw שתטופל ב-catch.

6. פונקציות async שמחזירות ערכים

פונקציה אסינכרונית מחזירה תמיד Promise. כאשר מחזירים ערך רגיל בתוך הפונקציה, הוא נעטף אוטומטית ב-Promise שמתקיים עם הערך המוחזר.

דוגמה:

async function calculate() {
    return 42;
}

calculate().then(result => console.log(result)); // מציג 42

הסבר:

  • הפונקציה calculate מוגדרת כ-async, ולכן היא מחזירה Promise.
  • הערך המוחזר (42) נעטף ב-Promise שמתקיים, ואנחנו מקבלים אותו דרך then.

7. המתנה למספר Promises במקביל עם await

אפשר להמתין למספר Promises במקביל בעזרת Promise.all, ולהשתמש ב-await כדי להמתין שכולם יסתיימו לפני שהקוד ממשיך.

דוגמה:

async function fetchMultiple() {
    let [post, user] = await Promise.all([
        fetch('https://jsonplaceholder.typicode.com/posts/1').then(res => res.json()),
        fetch('https://jsonplaceholder.typicode.com/users/1').then(res => res.json())
    ]);
    
    console.log("Post:", post);
    console.log("User:", user);
}

fetchMultiple();

הסבר:

  • הפונקציה fetchMultiple משתמשת ב-Promise.all כדי להפעיל שתי בקשות רשת במקביל.
  • עם await, אנחנו ממתינים עד ששתיהן יסתיימו לפני שהקוד ממשיך.
  • הפלט יכלול את התוצאות של שתי הבקשות.

8. דוגמה מלאה: תהליך אסינכרוני עם async ו-await

נבנה דוגמה שמדמה תהליך של בדיקת קובץ, הורדה שלו ועיבודו באמצעות async ו-await.

function checkFile() {
    return new Promise((resolve, reject) => {
        console.log("Checking file...");
        setTimeout(() => resolve("File exists"), 1000);
    });
}

function downloadFile() {
    return new Promise((resolve, reject) => {
        console.log("Downloading file...");
        setTimeout(() => resolve("File downloaded"), 2000);
    });
}

function processFile() {
    return new Promise((resolve, reject) => {
        console.log("Processing file...");
        setTimeout(() => resolve("File processed"), 1500);
    });
}

async function handleFile() {
    try {
        let fileCheck = await checkFile();
        console.log(fileCheck); // "File exists"
        
        let download = await downloadFile();
        console.log(download); // "File downloaded"
        
        let process = await processFile();
        console.log(process); // "File processed"
        
    } catch (error) {
        console.log("Error:", error);
    } finally {
        console.log("Process completed.");
    }
}

handleFile();

הסבר:

  • כל אחת מהפונקציות (checkFile, downloadFile, processFile) מחזירה Promise שמדמה פעולה אסינכרונית.
  • הפונקציה handleFile משתמשת ב-await כדי להמתין שהפעולות יסתיימו לפני שהקוד ממשיך.
  • טיפול בשגיאות מתבצע באמצעות try...catch, ופעולה סופית מתבצעת ב-finally.

סיכום

בפרק זה למדנו על:

  1. איך להשתמש ב-async כדי להגדיר פונקציות אסינכרוניות.
  2. איך להשתמש ב-await כדי להמתין לתוצאה של Promise לפני שהקוד ממשיך.
  3. איך לטפל בשגיאות בעזרת try...catch בתוך פונקציות אסינכרוניות.
  4. עבודה עם מספר Promises במקביל באמצעות Promise.all ו-await.
  5. בניית תהליכים אסינכרוניים קריאים ונוחים לניהול בעזרת async ו-await.

בפרק הבא נעמיק בנושא Object-Oriented JavaScript ונראה איך לעבוד עם מחלקות (Classes) וירושה (Inheritance) ב-JavaScript.

Scroll to Top
דילוג לתוכן