ข้อมูลเบื้องต้นเกี่ยวกับ fetch()

fetch() ให้คุณส่งคำขอเครือข่ายที่คล้ายคลึงกับ XMLHttpRequest (XHR) ได้ ความแตกต่างหลักๆ คือ Fetch API ใช้ Promises ซึ่งมี API ที่เรียบง่ายขึ้นเพื่อช่วยให้คุณหลีกเลี่ยงการถูกเรียกกลับที่ซับซ้อนใน XMLHttpRequest API

การรองรับเบราว์เซอร์

  • Chrome: 42
  • ขอบ: 14
  • Firefox: 39.
  • Safari: 10.1

แหล่งที่มา

หากคุณไม่เคยใช้ คำมั่นสัญญา ก่อนหน้านี้ โปรดดูความรู้เบื้องต้นเกี่ยวกับ JavaScript Promises

คำขอดึงข้อมูลพื้นฐาน

นี่คือตัวอย่างการใช้งานด้วย XMLHttpRequest ตามด้วย fetch เราต้องการขอ URL, รับคำตอบ และแยกวิเคราะห์ เป็นไฟล์ JSON

XMLHttpRequest

XMLHttpRequest ต้องการผู้ฟัง 2 คนเพื่อรับมือกับความสำเร็จ และข้อผิดพลาด รวมถึงการเรียกใช้ 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 ซึ่งหมายความว่าหลังจาก เราเรียกเมธอด 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 อนุญาตคำขอสำหรับเนื้อหาในต้นทางเดียวกันและต้นทางอื่นๆ ที่ แสดงผลส่วนหัว CORs ที่เหมาะสม
  • cors-with-forced-preflight ดำเนินการตรวจสอบล่วงหน้า ตรวจสอบ ก่อนส่งคำขอ
  • no-cors มีไว้เพื่อส่งคำขอไปยังต้นทางอื่นๆ ที่ไม่มี CORS ส่วนหัวและผลลัพธ์ในการตอบสนอง opaque แต่ตามที่ระบุไว้ สิ่งนี้ไม่ใช่ ที่เป็นไปได้ในขอบเขตทั่วโลกของหน้าต่างในขณะนี้

หากต้องการกำหนดโหมด ให้เพิ่มออบเจ็กต์ตัวเลือกเป็นพารามิเตอร์ที่ 2 ใน 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 ที่ได้รับการแก้ไขแล้วเป็น Promise.resolve() หรือ "คำสัญญา" ที่ถูกปฏิเสธ Promise.reject() นี่เป็นวิธีการแรกที่มีการเรียกใช้ในเชน fetch()

หาก Promise แก้ปัญหาได้ สคริปต์จะเรียกเมธอด json() ซึ่ง แสดงผล Promise ที่สองจากการเรียก response.json() และสร้าง ที่มี JSON ที่แยกวิเคราะห์แล้ว หากการแยกวิเคราะห์ล้มเหลว คำสัญญาจะเป็น ถูกปฏิเสธ และคำสั่งการตรวจจับจะทำงาน

โครงสร้างนี้ช่วยให้คุณแชร์ตรรกะกับคำขอดึงข้อมูลทั้งหมด ทำให้ สามารถดูแลรักษา อ่าน และทดสอบได้ง่ายขึ้น

คำขอ 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);
    });

ส่งข้อมูลเข้าสู่ระบบด้วยคำขอดึงข้อมูล

หากต้องการส่งคำขอดึงข้อมูลด้วยข้อมูลเข้าสู่ระบบ เช่น คุกกี้ ให้ตั้งค่าคำขอ ค่า credentials เป็น "include":

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