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

API ดึงข้อมูล() อยู่ในออบเจ็กต์หน้าต่างและต้องการแทนที่ XHR

XMLHttpRequest ขนาดยาว

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

การสนับสนุนเบราว์เซอร์

  • 42
  • 14
  • 39
  • 10.1

แหล่งที่มา

API การดึงข้อมูลมีให้ใช้งานในขอบเขต Service Worker ทั่วโลกตั้งแต่ Chrome 40 แต่จะเปิดใช้ในขอบเขตหน้าต่างใน Chrome 42 นอกจากนี้ยังมี polyfill by GitHub ที่แทนการดึงข้อมูลซึ่งคุณนำมาใช้ได้ในปัจจุบันอีกด้วย

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

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

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

XMLHttpRequest

XMLHttpRequest ต้องมีการตั้งค่า Listener 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);
    });

เราเริ่มต้นด้วยการตรวจสอบว่าสถานะการตอบกลับเป็น 200 ก่อนที่จะแยกวิเคราะห์การตอบกลับเป็น JSON

การตอบกลับของคำขอ fetch() เป็นออบเจ็กต์สตรีม ซึ่งหมายความว่าเมื่อเราเรียกใช้เมธอด json() ระบบจะแสดงผล Promise เนื่องจากการอ่านสตรีมเกิดขึ้นแบบไม่พร้อมกัน

ข้อมูลเมตาของการตอบกลับ

ในตัวอย่างก่อนหน้านี้ เราดูที่สถานะของออบเจ็กต์การตอบกลับ รวมถึงวิธีแยกวิเคราะห์การตอบกลับเป็น 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 เป็น response.type "basic", "cors" หรือ "opaque" types เหล่านี้จะระบุว่าแหล่งข้อมูลมาจากไหนและสามารถใช้เพื่อให้ทราบว่าคุณควรจัดการออบเจ็กต์คำตอบอย่างไร

เมื่อมีการส่งคำขอสำหรับทรัพยากรจากต้นทางเดียวกัน การตอบกลับจะมีประเภท basic และไม่มีข้อจำกัดเกี่ยวกับสิ่งที่คุณดูได้จากการตอบกลับ

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

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

สัญญาโซ่

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

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

มีโพลีฟิลไหม

GitHub มี Polyfill สำหรับการดึงข้อมูล H/T @Nexii เพื่อแจ้งเรื่องนี้

เหตุใดโปรแกรมทำงานของบริการจึงรองรับ "no-cors" แต่ไม่รองรับหน้าต่าง

สืบเนื่องจากข้อกังวลด้านความปลอดภัย คุณสามารถดูข้อมูลเพิ่มเติมที่นี่