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

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

Browser Support

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

Source

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

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

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

XMLHttpRequest

XMLHttpRequest ต้องมี Listener 2 รายเพื่อจัดการกรณีที่สำเร็จและกรณีที่เกิดข้อผิดพลาด รวมถึงการเรียกใช้ 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() ต้องใช้การเรียกเพียงครั้งเดียวเพื่อทำงานแบบเดียวกับตัวอย่าง XHR ในการประมวลผลการตอบกลับ ก่อนอื่นเราจะตรวจสอบว่าสถานะการตอบกลับคือ 200 จากนั้นแยกวิเคราะห์การตอบกลับเป็น JSON การตอบกลับคำขอ fetch() คือออบเจ็กต์ Stream ซึ่งหมายความว่าหลังจากที่เราเรียกใช้เมธอด json() ระบบจะแสดงผล Promise สตรีมจะเกิดขึ้นแบบอะซิงโครนัส

ข้อมูลเมตาของคำตอบ

ตัวอย่างก่อนหน้านี้แสดงสถานะของออบเจ็กต์ 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 แต่ตามที่ระบุไว้ การดำเนินการนี้ไม่สามารถทำได้ในขอบเขตส่วนกลางของหน้าต่างในขณะนี้

หากต้องการกำหนดโหมด ให้เพิ่มออบเจ็กต์ตัวเลือกเป็นพารามิเตอร์ที่ 2 ในคำขอ 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)
  });

การเชื่อมโยง Promise

ฟีเจอร์ที่ยอดเยี่ยมอย่างหนึ่งของ Promise คือความสามารถในการเชื่อมโยงเข้าด้วยกัน สำหรับ fetch() วิธีนี้จะช่วยให้คุณแชร์ตรรกะในคำขอดึงข้อมูลได้

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

หาก Promise แก้ไขได้ สคริปต์จะเรียกใช้เมธอด json() ซึ่งจะแสดงผล Promise รายการที่ 2 จากการเรียกใช้ response.json() และสร้างออบเจ็กต์ที่มี JSON ที่แยกวิเคราะห์แล้ว หากการแยกวิเคราะห์ไม่สำเร็จ ระบบจะปฏิเสธ Promise และเรียกใช้คำสั่ง 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(data => {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(error => {
    console.log('Request failed', error);
  });

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

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

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