الخطوات
-
1
أجرِ استدعاء fetch أساسياً
استدعِ
fetch(url)الذي يُعيد Promise ينتهي بكائنResponse. استدعِresponse.json()لتحليل الجسم — وهو أيضاً Promise. استخدمawaitللاثنين.javascriptasync function getUser() { const response = await fetch('https://api.github.com/users/octocat'); const data = await response.json(); console.log(data); } getUser(); -
2
تحقق من response.ok — fetch لا يُطلق استثناءً عند الأخطاء
إذا أعاد السيرفر 404 أو 500، فإن
fetchلا يزال ينجز الـ Promise. يُرفض Promise فقط عند أعطال الشبكة (انقطاع الاتصال، أخطاء DNS، حظر CORS). يجب التحقق منresponse.ok(صحيح للأكواد 200-299) أو منresponse.statusصراحةً، ثم إطلاق خطأ مخصص.javascriptasync function getUser(username) { const response = await fetch(`https://api.github.com/users/${username}`); if (!response.ok) { throw new Error(`HTTP error: ${response.status} ${response.statusText}`); } return response.json(); } -
3
غلّف كل شيء في try/catch
أخطاء الشبكة، وفشل تحليل JSON، وأي
throwصريح من الخطوة السابقة — كلها تظهر كـ Promises مرفوضة. يُعالجها جميعاً كتلةtry/catchواحدة في مكان واحد.javascriptasync function getUser(username) { try { const response = await fetch(`https://api.github.com/users/${username}`); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); renderUser(data); } catch (err) { showError(err.message); } } -
4
أظهر حالات التحميل والأخطاء
اعرض مؤشر التحميل قبل الطلب وأخفِه بعده. عند الخطأ، أظهر رسالة في الواجهة — لا تبتلع الأخطاء بصمت أبداً. ضع عنصر الخطأ في HTML مخفياً بشكل افتراضي.
javascriptconst output = document.getElementById('output'); const errorEl = document.getElementById('error'); const loader = document.getElementById('loader'); async function getUser(username) { loader.hidden = false; errorEl.hidden = true; output.hidden = true; try { const response = await fetch(`https://api.github.com/users/${username}`); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); renderUser(data); output.hidden = false; } catch (err) { errorEl.textContent = `Failed to load: ${err.message}`; errorEl.hidden = false; } finally { loader.hidden = true; } } -
5
اعرض البيانات في DOM بأمان
استخدم
textContentلأي نص مصدره المستخدم أو الـ API. يُهرّب HTML تلقائياً —innerHTMLلا يفعل ذلك، وقد يُنفّذ سكريبت إذا أعاد الـ API بيانات خبيثة. لا تستخدمinnerHTMLإلا حين تتحكم 100% في المحتوى.javascriptfunction renderUser(data) { const card = document.getElementById('user-card'); // Safe: textContent escapes HTML entities card.querySelector('.name').textContent = data.name ?? data.login; card.querySelector('.bio').textContent = data.bio ?? 'No bio.'; card.querySelector('.repos').textContent = `${data.public_repos} repositories`; // Safe for URLs you trust (keep validation tight in real apps) const avatar = card.querySelector('.avatar'); avatar.src = data.avatar_url; avatar.alt = `Avatar of ${data.login}`; } -
6
ألغِ الطلبات القديمة بـ AbortController
حين يكتب المستخدم استعلاماً جديداً قبل اكتمال السابق، يجب ألا يحل الرد القديم محل الجديد. يتيح لك
AbortControllerإلغاء الطلبات الجارية. أنشئ controller جديداً لكل استدعاء وألغِ السابق.javascriptlet currentController = null; async function searchUsers(query) { // Abort any in-flight request if (currentController) currentController.abort(); currentController = new AbortController(); try { const response = await fetch( `https://api.github.com/search/users?q=${encodeURIComponent(query)}`, { signal: currentController.signal } ); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); renderResults(data.items); } catch (err) { if (err.name === 'AbortError') return; // Expected — ignore showError(err.message); } } -
7
أرسل طلبات POST بجسم JSON
لطلبات POST/PUT/PATCH، مرر كائن خيارات ثانياً لـ
fetch. حوّل الجسم إلى نص بـ stringify، واضبطContent-Type: application/jsonحتى يُحللها السيرفر بشكل صحيح.javascriptasync function createRepo(name, isPrivate = false) { const response = await fetch('https://api.github.com/user/repos', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify({ name, private: isPrivate }), }); if (!response.ok) { const err = await response.json(); throw new Error(err.message ?? `HTTP ${response.status}`); } return response.json(); }
نصائح ومحاذير
- تحقق دائماً من <code>response.ok</code> قبل استدعاء <code>response.json()</code> — قد لا يكون جسم الرد 4xx/5xx بتنسيق JSON صالح.
- استخدم <code>encodeURIComponent()</code> على أي معامل URL مصدره المستخدم لمنع حقن URL.
- يخزّن المتصفح طلبات GET بقوة. أضف معامل لكسر التخزين المؤقت أو استخدم <code>cache: 'no-store'</code> في خيارات fetch حين تحتاج دائماً إلى بيانات حديثة.
- للطلبات المتزامنة المتعددة، <code>Promise.all([fetch(a), fetch(b)])</code> يُشغّلها بالتوازي وينتظر الجميع.
- تجنب إعادة جلب بيانات لم تتغير. Map بسيطة في الذاكرة مفهرسة بالـ URL تُشكّل تخزيناً مؤقتاً خفيفاً على جانب العميل.
خاتمة
تُغطي fetch API كل ما تحتاجه لطلبات HTTP في المتصفح، لكن عليك استخدامها بشكل صحيح. العادات الأساسية: تحقق من response.ok، غلّف بـtry/catch، اعرض بـtextContent، وألغِ بـAbortController. أتقن هذه الأربع ولن تحتاج إلى Axios في أغلب مشاريعك.