مقدمة إلىFetch()

تصل واجهة برمجة التطبيقاتFetch() في كائن النافذة وتتطلّع إلى استبدال طلبات XHR

طلب XMLHttpRequest طويل جدًا

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

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

  • 42
  • 14
  • 39
  • 10.1

المصدر

كانت Fetch API متاحة في نطاق مشغّل الخدمات العام منذ إصدار Chrome 40، ولكن سيتم تفعيلها في نطاق النافذة ضِمن Chrome 42. هناك أيضًا استخدام polyfill من GitHub بدلاً من استرجاعها ويمكنك استخدامها اليوم.

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

طلب الجلب الأساسي

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

XMLHttpRequest

يتطلب XMLHttpRequest ضبط المستمعين للتعامل مع حالات النجاح والخطأ وإجراء مكالمة إلى open() وsend(). مثال من مستندات MDN:

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

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

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

استدعاء

يبدو طلب الجلب الذي نقدمه على النحو التالي:

fetch('./api/some.json')
    .then(
    function(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(function(err) {
    console.log('Fetch Error :-S', err);
    });

نبدأ بالتحقق من أن حالة الاستجابة هي 200 قبل تحليل الرد بتنسيق JSON.

الاستجابة لطلب fetch() هي كائن Stream، ما يعني أنه عند استدعاء طريقة json()، يتم عرض "الوعد" لأنّ قراءة البث تتم بشكل غير متزامن.

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

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

fetch('users.json').then(function(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 متطابقتان تقريبًا باستثناء أنّ الردّ cors يحصر العناوين التي يمكنك عرضها بـ Cache-Control وContent-Language وContent-Type وExpires وLast-Modified وPragma.

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

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

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

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

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

سلسلة التعهدات

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

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

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(function(data) {
    console.log('Request succeeded with JSON response', data);
    }).catch(function(error) {
    console.log('Request failed', error);
    });

نحدد الدالة status التي تتحقق من response.status وتعرض نتيجة Promise.resolve() أو Promise.reject()، والتي تعرض الوعد الذي تم حله أو رفضه. هذه هي الطريقة الأولى التي نطلق عليها في سلسلة fetch(). وإذا تم حلّها، نستدعي بعد ذلك الطريقة json() التي تعرض أيضًا وعدًا من استدعاء response.json(). بعد ذلك، لدينا كائن من JSON التحليل. إذا فشل التحليل، يتم رفض الوعد وتنفيذ عبارة Catch

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

طلب 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(function (data) {
    console.log('Request succeeded with JSON response', data);
    })
    .catch(function (error) {
    console.log('Request failed', error);
    });

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

إذا أردت تقديم طلب استرجاع باستخدام بيانات اعتماد مثل ملفات تعريف الارتباط، عليك ضبط credentials للطلب على "include".

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

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

كيف يمكنني إلغاء طلبfetch()؟

لا تتوفّر حاليًا طريقة لإلغاء عملية الجلب، ولكن تتم مناقشة هذا الأمر على GitHub. H/T @jaffathecake لهذا الرابط

هل هناك رمز polyfill؟

يتضمّن GitHub رمز polyfill للجلب. H/T @Nexii على سبيل الإشارة إلى ذلك.

لماذا يتم توفير "no-cors" (بدون مساعدة) في مشغّلي الخدمات وليس في النوافذ؟

وهذا بسبب مشكلة تتعلّق بالأمان. ويمكنك الاطّلاع على مزيد من المعلومات هنا.