מבוא ל-fetch()

בעזרת fetch() אפשר לשלוח בקשות רשת בדומה ל-XMLHttpRequest (XHR). ההבדל העיקרי הוא ש-Fetch API משתמש ב-Promises, שכולל API פשוט יותר שעוזר לכם להימנע מקריאות חוזרות (callback) מורכבות ב-XMLHttpRequest API.

תמיכה בדפדפן

  • 42
  • 14
  • 39
  • 10.1

מקור

אם מעולם לא השתמשתם ב-Promises, כדאי לקרוא את המאמר Introduction to JavaScript Promises.

בקשת אחזור בסיסית

זוהי דוגמה שמוטמעת באמצעות 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);
  });

הבקשה fetch() צריכה רק קריאה אחת כדי לבצע את אותה פעולה כמו בדוגמה של ה-XHR. כדי לעבד את התשובה, אנחנו קודם בודקים שסטטוס התגובה הוא 200, ולאחר מכן מנתחים את התגובה כ-JSON. התגובה לבקשת fetch() היא אובייקט Stream, כלומר אחרי שאנחנו קוראים ל-method json(), מוחזרת Promise. הסטרימינג מתבצע באופן אסינכרוני.

מטא-נתונים של תשובות

בדוגמה הקודמת הוצג הסטטוס של האובייקט 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, אבל הן מגבילות את הכותרות שאפשר להציג ל-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)
    });

שרשרת הבטחות

אחת התכונות הנפלאות של הבטחות היא היכולת לחבר אותן יחד. כך ניתן לשתף לוגיקה בין בקשות האחזור של fetch().

אם אתם עובדים עם JSON API, צריך לבדוק את הסטטוס ולנתח את ה-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

לפעמים אפליקציית אינטרנט צריכה לקרוא ל-API באמצעות שיטת 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);
    });

שליחת פרטי כניסה עם בקשת אחזור

כדי לשלוח בקשת אחזור עם פרטי כניסה כמו קובצי cookie, הגדירו את הערך בשדה credentials של הבקשה ל-"include":

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