| العنصر | الوظيفة |
|---|---|
| fetch(url) | إرسال طلب وإعادة Promise لكائن Response |
| response.ok | true إذا كانت حالة HTTP بين 200-299 |
| response.json() | تحليل جسم الاستجابة كـ JSON (Promise آخر) |
| method: "POST" | تحديد نوع الطلب عند إرسال بيانات |
Ajax اختصار لـ Asynchronous JavaScript and XML، وهو مصطلح عام يشير لتقنية جلب أو إرسال بيانات إلى خادم في الخلفية دون الحاجة لإعادة تحميل الصفحة بالكامل — وهذا ما يجعل تطبيقات الويب الحديثة تبدو وتتصرف مثل تطبيقات سطح المكتب السلسة. تاريخياً استُخدم كائن XMLHttpRequest لتحقيق هذا، لكنه كان معقداً وطويلاً في الاستخدام.
Fetch API هي الواجهة الحديثة والمعيارية المدمجة في كل متصفح لتحقيق هذا الغرض، وتعتمد بالكامل على Promises مما يجعلها تتكامل بسلاسة تامة مع async/await. تستدعي fetch() برابط (URL) كوسيط أول، وهي تُعيد Promise يحلّ إلى كائن Response يمثل استجابة الخادم الأولية — لكن هذا الكائن لا يحتوي البيانات الفعلية مباشرة، بل يحتاج خطوة إضافية لاستخراجها حسب نوعها، الأكثر شيوعاً عبر response.json() التي تُعيد بدورها Promise آخر يحلّ للبيانات الفعلية بعد تحليلها.
نقطة مهمة جداً يقع فيها كثير من المبتدئين: fetch() لا يرفض الـ Promise (لا يدخل في catch) عند استجابة خادم بحالة خطأ HTTP مثل 404 أو 500 — فقط يرفض عند فشل الشبكة نفسها (كانقطاع الاتصال). لهذا يجب دائماً التحقق يدوياً من response.ok (قيمة منطقية true للحالات 200-299) قبل معالجة البيانات، ورمي خطأ يدوياً إن لم تكن الاستجابة ناجحة.
لإرسال بيانات للخادم (وليس فقط جلبها)، تمرر لـ fetch() وسيطاً ثانياً هو كائن خيارات يحتوي method (مثل "POST" أو "PUT" أو "DELETE")، وheaders لتحديد نوع المحتوى المُرسَل (عادة "Content-Type": "application/json")، وbody الذي يحتوي البيانات الفعلية المُرسلة بعد تحويلها لنص JSON عبر JSON.stringify().
| 1 | // جلب بيانات (GET) — الحالة الافتراضية |
| 2 | async function جلب_المنتجات() { |
| 3 | const استجابة = await fetch("/api/products"); |
| 4 | if (!استجابة.ok) throw new Error("فشل الجلب: " + استجابة.status); |
| 5 | return await استجابة.json(); |
| 6 | } |
| 7 | |
| 8 | // إرسال بيانات (POST) |
| 9 | fetch("/api/products", { |
| 10 | method: "POST", |
| 11 | headers: { "Content-Type": "application/json" }, |
| 12 | body: JSON.stringify({ اسم: "منتج جديد", سعر: 99 }), |
| 13 | }); |
مثال 1: التحقق الصحيح من نجاح استجابة fetch
| 1 | // التعامل الصحيح مع أخطاء HTTP (نقطة يخطئ فيها كثيرون) |
| 2 | async function جلب_مستخدم(id) { |
| 3 | try { |
| 4 | const استجابة = await fetch(`/api/users/${id}`); |
| 5 | |
| 6 | if (!استجابة.ok) { |
| 7 | throw new Error(`خطأ HTTP: ${استجابة.status}`); |
| 8 | } |
| 9 | |
| 10 | const مستخدم = await استجابة.json(); |
| 11 | return مستخدم; |
| 12 | } catch (خطأ) { |
| 13 | console.error("فشل جلب المستخدم:", خطأ.message); |
| 14 | return null; |
| 15 | } |
| 16 | } |
مثال 2: إرسال بيانات POST كاملة بمعالجة أخطاء
| 1 | // إرسال نموذج جديد (POST) وقراءة النتيجة |
| 2 | async function إضافة_مستخدم(بيانات) { |
| 3 | const استجابة = await fetch("/api/users", { |
| 4 | method: "POST", |
| 5 | headers: { "Content-Type": "application/json" }, |
| 6 | body: JSON.stringify(بيانات), |
| 7 | }); |
| 8 | |
| 9 | if (!استجابة.ok) { |
| 10 | const خطأ = await استجابة.json(); |
| 11 | throw new Error(خطأ.message || "فشلت الإضافة"); |
| 12 | } |
| 13 | return await استجابة.json(); |
| 14 | } |
| 15 | |
| 16 | إضافة_مستخدم({ اسم: "نورا", البريد: "nora@example.com" }) |
| 17 | .then(مستخدم_جديد => console.log("تمت الإضافة:", مستخدم_جديد)) |
| 18 | .catch(خطأ => console.error(خطأ.message)); |