0Pricing
Frontend Academy · درس

async/await ومعالجة الأخطاء

اكتب دوال async باستخدام الكلمة المفتاحية await، وضع الاستدعاءات المنتظرة داخل كتل try/catch، وافهم أن async/await صياغة مختصرة مبنية على Promises.

async/await ومعالجة الأخطاء درس مجاني في Frontend Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Frontend Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Frontend Academy 4 دروس في المجموع.

ما هي async/await؟

تُعدّ async/await صياغة نحوية مختصرة فوق Promises. تعيد دالة async دائمًا Promise. وتوقف الكلمة المفتاحية await الدالة مؤقتًا حتى تستقر Promise المنتظرة. تبدو الشفرة متزامنة، لكنها تعمل بصورة غير متزامنة.

دالة async

أضيفوا الكلمة المفتاحية async قبل تعريف الدالة أو تعبيرها. عندئذٍ تغلف الدالة قيمة الإرجاع ضمنيًا داخل Promise.

async function fetchUser(id) {
  // implicitly returns a Promise
  return { id, name: 'Alice' };
}

// Equivalent to:
function fetchUser(id) {
  return Promise.resolve({ id, name: 'Alice' });
}

await — التوقف مؤقتًا لانتظار Promises

لا يمكن استخدام await إلا داخل دالة async. وهي توقف التنفيذ مؤقتًا حتى تُحلّ Promise، ثم تعيد القيمة الناتجة. ويستمر تشغيل الشفرة الأخرى في حلقة الأحداث.

async function loadProfile(id) {
  const user = await fetchUser(id);     // waits for Promise
  const posts = await fetchPosts(user.id); // waits again
  return { user, posts };
}

الانتظار المتسلسل مقابل الانتظار المتوازي

الانتظار بالتسلسل سهل القراءة، لكنه بطيء إذا لم تكن المهام تعتمد بعضها على بعض. استخدموا Promise.all() لانتظار عدة مهام مستقلة بالتوازي.

// Sequential (slow if tasks are independent):
const user = await fetchUser(id);
const settings = await fetchSettings(id); // waits for user unnecessarily

// Parallel (fast):
const [user, settings] = await Promise.all([
  fetchUser(id),
  fetchSettings(id),
]);

try/catch لمعالجة الأخطاء

غلّفوا الاستدعاءات المنتظرة داخل try/catch لمعالجة حالات الرفض. وتتلقى كتلة catch سبب الرفض في صورة كائن خطأ.

async function saveUser(data) {
  try {
    const response = await fetch('/api/users', {
      method: 'POST',
      body: JSON.stringify(data),
      headers: { 'Content-Type': 'application/json' }
    });
    if (!response.ok) throw new Error(`Server error ${response.status}`);
    return await response.json();
  } catch (err) {
    console.error('Save failed:', err.message);
    throw err; // re-throw so caller can handle
  }
}

await على المستوى الأعلى

في وحدات ES (وليس CommonJS)، يمكنكم استخدام await على المستوى الأعلى من دون تغليفه داخل دالة async. ويفيد ذلك في تهيئة الوحدة.

// module.js (ES module)
const config = await fetch('/config.json').then(r => r.json());
export const API_URL = config.apiUrl;

async/await مع forEach — مأزق شائع

لا تنتظر Array.forEach() دوال رد الاتصال غير المتزامنة. استخدموا for...of للتكرار غير المتزامن المتسلسل، أو Promise.all(arr.map(...)) للتنفيذ بالتوازي.

// WRONG — forEach doesn't await:
items.forEach(async (item) => {
  await processItem(item); // runs but forEach doesn't wait
});

// CORRECT — sequential:
for (const item of items) {
  await processItem(item);
}

// CORRECT — parallel:
await Promise.all(items.map(item => processItem(item)));

كائنات الأخطاء والأخطاء المخصصة

استخدموا throw دائمًا مع كائنات Error (وليس السلاسل النصية) للحفاظ على تتبعات مكدس الاستدعاءات. أنشئوا فئات أخطاء مخصصة للأخطاء الخاصة بالمجال، بحيث يتمكن المستدعون من التقاطها حسب النوع.

class NetworkError extends Error {
  constructor(message, status) {
    super(message);
    this.name = 'NetworkError';
    this.status = status;
  }
}

try {
  const res = await fetch(url);
  if (!res.ok) throw new NetworkError(`Failed`, res.status);
} catch (err) {
  if (err instanceof NetworkError && err.status === 401) {
    redirectToLogin();
  } else {
    throw err;
  }
}

finally في async/await

تُنفَّذ كتلة finally سواء نجحت try أو فشلت — تمامًا مثل .finally() في Promise. استخدموها لتحرير الموارد أو إخفاء حالات التحميل.

async function loadData() {
  setLoading(true);
  try {
    const data = await fetch('/api/data').then(r => r.json());
    setData(data);
  } catch (err) {
    setError(err.message);
  } finally {
    setLoading(false); // always runs
  }
}

IIFE غير متزامنة لنقاط دخول الوحدات

غلّفوا نقطة دخول البرنامج النصي داخل IIFE غير متزامنة عندما لا يمكنكم استخدام await على المستوى الأعلى.

(async () => {
  const data = await fetchInitialData();
  renderApp(data);
})();

AbortController للإلغاء

مرّروا إشارة AbortController إلى fetch لإلغاء طلب قيد التنفيذ. ويمنع التقاط AbortError بصورة منفصلة عرض خطأ للمستخدم.

const controller = new AbortController();

try {
  const data = await fetch(url, { signal: controller.signal }).then(r => r.json());
  setData(data);
} catch (err) {
  if (err.name !== 'AbortError') setError(err.message);
}

// Cancel:
controller.abort();

اختبار سريع

أي تركيب يعالج الأخطاء الناتجة عن Promise منتظرة بصورة صحيحة؟

مراجعة: async/await

تعيد دوال async دائمًا Promises. توقف await التنفيذ مؤقتًا حتى تستقر Promise. استخدموا try/catch لمعالجة الأخطاء. وللعمليات المتوازية استخدموا Promise.all(). تجنبوا استخدام await داخل forEach — واستخدموا for...of أو Promise.all بدلًا من ذلك. يلغي AbortController الطلبات قيد التنفيذ. ويعمل await على المستوى الأعلى في وحدات ES.

الأسئلة الشائعة

هل درس «async/await ومعالجة الأخطاء» مجاني؟

نعم — نص درس «async/await ومعالجة الأخطاء» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Frontend Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Frontend Academy 4 دروس في المجموع.

ماذا ستتعلم في «async/await ومعالجة الأخطاء»؟

اكتب دوال async باستخدام الكلمة المفتاحية await، وضع الاستدعاءات المنتظرة داخل كتل try/catch، وافهم أن async/await صياغة مختصرة مبنية على Promises. تتمرن على Frontend Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Frontend Academy؟

لا تُشترط خبرة سابقة. Frontend Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «async/await ومعالجة الأخطاء»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Frontend Academy هذا؟

نعم. كل درس في Frontend Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. حلقة الأحداث: مكدس الاستدعاءات وطابور المهام والمهام المصغّرة
  2. دوال الاستدعاء وجحيم الاستدعاءات
  3. Promises: then وcatch وfinally وPromise.all
  4. async/await ومعالجة الأخطاء
← العودة إلى Frontend Academy