الواجهة البرمجية fetch في JavaScript


سارة محمد2

إحدى أسوأ الأسرار التي تمَّ الاحتفاظ بها حول AJAX على الويب هو أنّ الواجهة البرمجية (API) الأساسية لها، XMLHttpRequest، لم توجد للغرض الذي نستخدمه الآن. لقد قمنا بعمل جيد في إنشاء واجهة برمجية جيّدة باستخدام الكائن XHR ولكننا نعرف أنه يمكننا القيام بعمل أفضل. نحن نبذل الجهود لتحقيق الأفضل الذي هو الواجهة البرمجية fetch. لنأخذ فكرة عامة عن التابع window.fetch الجديد، المتوفر الآن في Firefox و Chrome Canary.

الكائن XMLHttpRequest

إنَّ كائن XHR معقد قليلًا برأيي ولا أريد أن أبدأ بشرح لماذا "XML" تُكتب بأحرف كبيرة بينما "Http" تُكتب بأسلوب سنام الجمل. على أيّة حال، لنلاحظ كيف نستخدم XHR.

// فوضى XHR فقط الحصول على  
if (window.XMLHttpRequest) { // موزيلا، سفاري...
  request = new XMLHttpRequest();
} else if (window.ActiveXObject) { // إنترنت إكسبلورر
  try {
    request = new ActiveXObject('Msxml2.XMLHTTP');
  } 
  catch (e) {
    try {
      request = new ActiveXObject('Microsoft.XMLHTTP');
    } 
    catch (e) {}
  }
}

// فتح، إرسال
request.open('GET', 'https://davidwalsh.name/ajax-endpoint', true);
request.send(null);

بالطبع إنَّ أطر عمل جافاسكربت الخاصة بنا تجعل XHR أكثر متعة للعمل، ولكن ما نراه في الأعلى هو مثال بسيط على فوضى XHR.

استخدام fetch الأساسي

تم توفير دالة fetch في نطاق window العام، الوسيط الأول له هو الرابط URL:

// الرابط (إلزامي)، الخيارات (اختيارية)
fetch('https://davidwalsh.name/some/url', {
    method: 'get'
}).then(function(response) {

}).catch(function(err) {
    // خطأ :(
});

وهذا يشبه إلى حد بعيد الواجهة البرمجية Battery المحدّثة، إذ تستخدم الواجهة البرمجية fetch الوعود في جافاسكربت لمعالجة النتائج/ردود النداء:

// معالجة رد بسيط
fetch('https://davidwalsh.name/some/url').then(function(response) {

}).catch(function(err) {
    // خطأ :(
});

// "تسلسل لمعالجة أكثر "تطورًا
fetch('https://davidwalsh.name/some/url').then(function(response) {
    return //...
}).then(function(returnedValue) {
    // ...
}).catch(function(err) {
    // خطأ :(
});

إذا لم تكن معتادًا على استخدام then، يجب أن تعتاد عليه لأنها ستنتشر قريبًا في كلّ مكان.

ترويسات الطلب

القدرة على ضبط ترويسات الطلب هي أمر مهم في مرونة الطلب. يمكنك العمل مع ترويسات الطلب بتنفيذ new Headers()‎:

// إنشاء كائن ترويسة فارغ
var headers = new Headers();

// إضافة بعض الترويسات
headers.append('Content-Type', 'text/plain');
headers.append('X-My-Custom-Header', 'CustomValue');

// للترويسة set و get و check قيم
headers.has('Content-Type'); // true
headers.get('Content-Type'); // "text/plain"
headers.set('Content-Type', 'application/json');

// حذف ترويسة
headers.delete('X-My-Custom-Header');

// إضافة قيم ابتدائية
var headers = new Headers({
    'Content-Type': 'text/plain',
    'X-My-Custom-Header': 'CustomValue'
});

يمكنك استخدام التوابع append و has و get و set و delete لتعديل ترويسات الطلب. لاستخدام ترويسات الطلب أنشئ الكائن Request:

var request = new Request('https://davidwalsh.name/some-url', {
    headers: new Headers({
        'Content-Type': 'text/plain'
    })
});

fetch(request).then(function() { /* معالجة الرد*/ });

لنطّلع على عمل الكائنين Response و Request.

الكائن Request

يمثّل الكائن Request جزء الطلب عند استدعاء التابع fetch، يمكنك إنشاء طلبات مخصصة ومتطورة بتمرير الكائن Request للتابع fetch:

  • method (الطريقة): يمكن أن تكون GET أو POST أو PUT أو DELETE أو HEAD
  • url (الرابط): رابط الطلب
  • headers (الترويسة): ترتبط مع الكائن Headers
  • referrer (المرجع): مرجع الطلب
  • mode (النمط): يكون cors أو no-cors أو same-origin
  • credentials (بيانات الاعتماد): هل تعمل ملفات تعريف الارتباط (cookies) مع الطلب؟ وتأخذ إحدى القيمتين omit، أو same-origin.
  • redirect (إعادة التوجيه): يمكن أن يأخذ القيمة follow أو error أو manual.
  • integrity (التكامل): قيمة تكامل المصدر الفرعي.
  • cache (التخزين المؤقت): وضع التخزين المؤقت ويمكن أن يأخذ إحدى القيم default أو reload أو no-cache عينة عن استخدام الكائن Request:
var request = new Request('https://davidwalsh.name/users.json', {
    method: 'POST', 
    mode: 'cors', 
    redirect: 'follow',
    headers: new Headers({
        'Content-Type': 'text/plain'
    })
});

// الآن استخدمه
fetch(request).then(function() { /* معالجة الرد */ });

الوسيط الأول URL هو فقط الوسيط الإلزامي، وكل خاصية تصبح للقراءة فقط حالما يتم إنشاء نسخة من الكائن Request، ومن المهم أن نلاحظ أن الكائن Request يملك التابع clone المهم عند استخدام fetch ضمن الواجهة البرمجية Service Worker -- يعد الكائن Request مجرًى ولهذا يجب أن يتم نسخه عند تمريره إلى استدعاء آخر للتابع fetch.

بصمة التابع fetch ولكن نفس استخدام الكائن Request لذا يمكنك القيام بما يلي:

fetch('https://davidwalsh.name/users.json', {
    method: 'POST', 
    mode: 'cors', 
    redirect: 'follow',
    headers: new Headers({
        'Content-Type': 'text/plain'
    })
}).then(function() { /* معالجة الرد */ });

من المحتمل أن تستخدم نسخًا من الكائن Request فقط ضمن Service Workers بما أن الكائن Request والتابع fetch يؤديان نفس الوظيفة.

الكائن Response

التابع then الذي يخص fetch مزود بالكائن Response ولكن يمكنك أيضًا إنشاء كائنات Response بنفسك -- حالة أخرى قد تواجهها عند استخدام service workers. يمكنك ضبط ما يلي عند استخدام الكائن Response:

  • type (النوع): يمكن أن يكون basic أو cors
  • url (الرابط)
  • useFinalURL (استخدام الرابط النهائي): قيمة منطقية للرابط url إذا كان رابطًا نهائيًا أم لا
  • status (الحالة): رمز الحالة (مثلًا 200، 400)
  • ok: قيمة منطقية للاستجابة الناجحة (الحالة في المجال بين 200- 299)
  • statusText (نص الحالة): نص يعبّر عن الحالة وفقًا للرمز (مثلًا: OK)
  • headers (الترويسة): كائن Headers المرتبط بالاستجابة
// service worker أنشئ ردك لاختبار 
// جديد (الجسم، الخيارات) Response كائن 
var response = new Response('.....', {
    ok: false,
    status: 404,
    url: '/'
});

// Response يجلب مجدَّدًا نسخة من  الكائن fetch الذي يخص then التابع
fetch('https://davidwalsh.name/')
.then(function(responseObj) {
    console.log('status: ', responseObj.status);
});

يوفر الكائن Response أيضًا الطرائق التالية:

  • clone()‎: تُنشئ نسخة من الكائن Response
  • ()error: تعيد كائن Response جديد مرتبط مع خطأ في الشبكة
  • ()redirect: تنشئ استجابة جديدة مع رابط URL مختلف
  • ()arrayBuffer: تعيد وعدًا يُقبل (resolve) مع ArrayBuffer
  • ()blob: تعيد وعدًا يُقبل (resolve) مع Blob
  • ()formData: تعيد وعدًا يُقبل (resolve) مع كائن FormData
  • ()json: تعيد وعدًا يُقبل (resolve) مع كائن JSON
  • ()text: تعيد وعدًا يُقبل (resolve) مع القيمة النصية USVString

التعامل مع JSON

بفرض أنّك أنشأت طلب لـJSON -- معلومات نتيجة ردود النداء لديها التابع json لتحويل البيانات الخام إلى كائن جافاسكربت:

fetch('https://davidwalsh.name/demo/arsenal.json').then(function(response) { 
    // JSON التحويل إلى 
    return response.json();
}).then(function(j) {
    // هو كائن جافاسكربت j
    console.log(j); 
});

بالطبع هذا سهل JSON.parse(jsonString) لكن طريقة json تعد اختصارًا سهلًا.

التعامل مع استجابات Text/HTML الأساسية

ليست دائما JSON هي صيغة رد الطلب المرغوبة لذا إليك كيف نجعل الاستجابة على شكل نص أو HTML:

fetch('/next/page')
  .then(function(response) {
    return response.text();
  }).then(function(text) { 
      // <!DOCTYPE ....
      console.log(text); 
  });

بإمكانك الحصول على استجابة نصية عبر تسلسل طريقة then للوعد مع طريقة text()‎.

التعامل مع استجابات بشكل بيانات ثنائية

إذا كنت ترغب مثلًا بتحميل صورة باستخدام التابع fetch فإن هذا سيكون مختلفًا.

fetch('https://davidwalsh.name/flowers.jpg')
    .then(function(response) {
      return response.blob();
    })
    .then(function(imageBlob) {
      document.querySelector('img').src = URL.createObjectURL(imageBlob);
    });

يأخذ التابع blob()‎ تدفق الاستجابة وتقرأه حتى يكتمل.

الحصول على بيانات النموذج

استخدام آخر شائع للـAJAX وهو إرسال بيانات نموذج، وإليك كيف يمكن أن نستخدم التابع fetch للحصول على بيانات نموذج مرسلة بالطريقة POST:

fetch('https://davidwalsh.name/submit', {
    method: 'post',
    body: new FormData(document.getElementById('comment-form'))
});

وإذا أردت إرسال البيانات بصيغة JSON إلى الخادم:

fetch('https://davidwalsh.name/submit-json', {
    method: 'post',
    body: JSON.stringify({
        email: document.getElementById('email').value,
        answer: document.getElementById('answer').value
    })
});

سهل جدًا ومريح للعينين أيضًا.

قصة لم تُكتب

رغم أن fetch هي واجهة برمجية سهلة الاستخدام، إلا أنّ الواجهة البرمجية الحالية لا تسمح بإلغاء الطلب مما يجعلها غير مستخدمة لكثير من المطورين.

إن الواجهة البرمجية fetch الجديدة تبدو أفضل وأسهل استخدامًا من XHR. وبعد كل ذلك تمّ إنشاؤها حتى نتمكّن من استخدام AJAX بالطريقة الصحيحة. تملك fetch فوائد الخبرات السابقة، ولا أطيق الانتظار حتى يتم استخدامها على نطاق واسع.

ترجمة -وبتصرف- للمقال ‎fetch API لصاحبه David Walsh





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن