مقدمة إلىFetch()

fetch() يتيح لك تقديم طلبات إلى الشبكة مشابهة لطلبات XMLHttpRequest (XHR). ويتمثل الاختلاف الرئيسي في أنّ واجهة برمجة التطبيقات Fetch API تستخدم وعدًا، والذي يحتوي على واجهة برمجة تطبيقات أبسط لمساعدتك في تجنُّب عمليات الاستدعاء المعقّدة في واجهة برمجة التطبيقات XMLHttpRequest API.

توافق المتصفّح

  • Chrome: 42
  • ‫Edge: 14
  • Firefox: 39
  • ‫Safari: 10.1

المصدر

إذا لم يسبق لك استخدام الوعد من قبل، اطّلِع على مقدّمة عن وعد JavaScript.

طلب استرجاع أساسي

في ما يلي مثال تم تنفيذه باستخدام XMLHttpRequest ثم باستخدام fetch. نريد طلب عنوان URL والحصول على استجابة وتحليله بتنسيق JSON.

XMLHttpRequest

يحتاج XMLHttpRequest إلى مستمعَين للتعامل مع حالات النجاح والخطأ، وطلب open() وsend(). مثال من مستندات MDN

function reqListener () {
  const data = JSON.parse(this.responseText);
  console.log(data);
}

function reqError (err) {
  console.log('Fetch Error :-S', err);
}

const oReq = new XMLHttpRequest();
oReq.onload = reqListener;
oReq.onerror = reqError;
oReq.open('get', './api/some.json', true);
oReq.send();

جلب

يبدو طلب الجلب على النحو التالي:

fetch('./api/some.json')
  .then(response => {
    if (response.status !== 200) {
      console.log(`Looks like there was a problem. Status Code: ${response.status}`);

      return;
    }

    // Examine the text in the response
    response.json().then(function(data) {
      console.log(data);
    });
  })
  .catch(err => {
    console.log('Fetch Error :-S', err);
  });

لا يحتاج طلب fetch() إلى سوى طلب واحد لتنفيذ العمل نفسه الذي يؤديه مثال fetch(). لمعالجة الاستجابة، نتحقّق أولاً من أنّ حالة الاستجابة هي 200، ثمّ نفكّك الاستجابة بتنسيق JSON. الاستجابة لطلب fetch() هي كائن Stream، ما يعني أنّه بعد استدعاء الطريقة json()، يتم عرض وعد. يتم البث بشكل غير متزامن.

البيانات الوصفية للردّ

عرض المثال السابق حالة كائن Response وكيفية تحليل الاستجابة بتنسيق JSON. في ما يلي كيفية التعامل مع البيانات الوصفية الأخرى التي قد تريد الوصول إليها، مثل العناوين:

fetch('users.json').then(response => {
  console.log(response.headers.get('Content-Type'));
  console.log(response.headers.get('Date'));

  console.log(response.status);
  console.log(response.statusText);
  console.log(response.type);
  console.log(response.url);
});

أنواع الردود

عند تقديم طلب استرجاع، سيتم منح الردّ response.type من "basic"، "cors" أو "opaque". توضّح هذه types مصدر المورد، ويمكنك استخدامها لتحديد كيفية التعامل مع عنصر الردّ.

عندما يطلب المتصفّح موردًا من المصدر نفسه، يكون للردّ نوع basic مع قيود على ما يمكنك الاطّلاع عليه من الاستجابة.

إذا تم تقديم طلب لمورد على مصدر آخر، وأعاد هذا المصدر عناوين CORs، يكون النوع هو cors. تشبه استجابات cors استجابات basic، ولكنّها تحدّ من العناوين التي يمكنك عرضها إلى Cache-Control وContent-Language وContent-Type وExpires وLast-Modified وPragma.

تأتي استجابات opaque من مصدر مختلف لا يعرض عناوين CORS. في حال تلقّي ردّ غير واضح، لن نتمكّن من قراءة البيانات التي تم عرضها أو الاطّلاع على حالة الطلب، ما يعني أنّه لا يمكنك التحقّق مما إذا كان الطلب ناجحًا.

يمكنك تحديد وضع لطلب استرجاع كي يتم حلّ أنواع طلبات معيّنة فقط. في ما يلي الأوضاع التي يمكنك ضبطها:

  • لا تنجح same-origin إلا لطلبات مواد العرض على المصدر نفسه، و ترفض جميع الطلبات الأخرى.
  • cors يسمح بطلبات مواد العرض من المصدر نفسه والمصادر الأخرى التي تُعيد عناوين CORs المناسبة.
  • يُجري cors-with-forced-preflight فحصًا للإعداد المُسبَق قبل تقديم أي طلب.
  • يهدف no-cors إلى إرسال طلبات إلى مصادر أخرى لا تحتوي على رؤوس CORS مما يؤدي إلى تلقّي استجابة opaque، ولكن كما هو موضّح، لا يمكن إجراء ذلك في النطاق الشامل للنافذة في الوقت الحالي.

لتحديد الوضع، أضِف عنصر خيارات كمَعلمة ثانية في طلب fetch وحدِّد الوضع في هذا العنصر:

fetch('http://some-site.com/cors-enabled/some.json', {mode: 'cors'})
  .then(response => response.text())
  .then(text => {
    console.log('Request successful', text);
  })
  .catch(error => {
    log('Request failed', error)
  });

سلسلة الوعود

من الميزات الرائعة للوعود هي إمكانية ربطها ببعضها. بالنسبة إلى fetch()، يتيح لك ذلك مشاركة المنطق على مستوى طلبات الجلب.

إذا كنت تستخدم واجهة برمجة تطبيقات JSON، عليك التحقّق من الحالة وتحليل ملف ملف JSON لكل استجابة. يمكنك تبسيط الرمز البرمجي من خلال تحديد الحالة وتحليل ملف JSON في دوال منفصلة تعرض الوعود، واستخدام طلب fetch للتعامل مع البيانات النهائية وحالة الخطأ فقط.

function status (response) {
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
  } else {
    return Promise.reject(new Error(response.statusText))
  }
}

function json (response) {
  return response.json()
}

fetch('users.json')
  .then(status)
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  }).catch(error => {
    console.log('Request failed', error);
  });

يحدِّد هذا المثال دالة status تتحقّق من response.status و تعرِض إما وعدًا تم حلّه على النحو التالي: Promise.resolve()، أو وعدًا مرفوضًا على النحو التالي: Promise.reject(). هذه هي الطريقة الأولى التي يتمّ استدعاؤها في سلسلة fetch().

إذا تم حلّ الوعد، يستدعي النص البرمجي الطريقة json() التي تُعيد وعدًا ثانيًا من طلب response.json() وتُنشئ عنصرًا يحتوي على ملف JSON الذي تم تحليله. إذا تعذّر التحليل، يتم رفض الوعد ويُنفَّذ بيان المعالجة.

تتيح لك هذه البنية مشاركة المنطق في جميع طلبات الجلب، ما يسهّل صيانة الرمز البرمجي وقراءته واختباره.

طلب POST

في بعض الأحيان، يحتاج تطبيق الويب إلى استدعاء واجهة برمجة تطبيقات باستخدام طريقة POST وتضمين بعض المَعلمات في نص الطلب. لإجراء ذلك، اضبط المَعلمتَين method وbody في خيارات fetch():

fetch(url, {
    method: 'post',
    headers: {
      "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
    },
    body: 'foo=bar&lorem=ipsum'
  })
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(error => {
    console.log('Request failed', error);
  });

إرسال بيانات الاعتماد مع طلب استرجاع

لتقديم طلب استرجاع باستخدام بيانات اعتماد مثل ملفات تعريف الارتباط، اضبط قيمة credentials للطلب على "include":

fetch(url, {
  credentials: 'include'
})