กำลังให้บริการ

แง่มุมสำคัญของ Progressive Web App คือมีความเสถียร แอปสามารถโหลดเนื้อหาได้อย่างรวดเร็ว ทำให้ผู้ใช้มีส่วนร่วมและแสดงความคิดเห็นได้ทันที แม้ในสภาพเครือข่ายไม่ดี เป็นไปได้อย่างไร มีเหตุการณ์ fetch สำหรับ Service Worker

เหตุการณ์การดึงข้อมูล

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

  • 40
  • 17
  • 44
  • 11.1

แหล่งที่มา

เหตุการณ์ fetch ช่วยให้เราสกัดกั้นทุกคำขอเครือข่ายที่ PWA สร้างขึ้นในขอบเขตของ Service Worker สำหรับทั้งคำขอต้นทางเดียวกันและข้ามต้นทาง นอกจากการนำทางและคำขอเนื้อหาแล้ว การดึงข้อมูลจาก Service Worker ที่ติดตั้งไว้จะทำให้การเข้าชมหน้าเว็บหลังจากการโหลดครั้งแรกของเว็บไซต์แสดงผลได้โดยไม่ต้องใช้การเรียกใช้เครือข่าย

ตัวแฮนเดิล fetch จะได้รับคำขอทั้งหมดจากแอป ซึ่งรวมถึง URL และส่วนหัว HTTP และช่วยให้นักพัฒนาแอปเลือกวิธีประมวลผลคำขอได้

โดยมี Service Worker อยู่ระหว่างไคลเอ็นต์และเครือข่าย

Service Worker สามารถส่งต่อคำขอไปยังเครือข่าย ตอบกลับด้วยการตอบกลับที่แคชไว้ก่อนหน้านี้ หรือสร้างการตอบกลับใหม่ได้ ทั้งนี้ขึ้นอยู่กับการตัดสินใจของคุณ ต่อไปนี้เป็นตัวอย่างง่ายๆ

self.addEventListener("fetch", event => {
    console.log(`URL requested: ${event.request.url}`);
});

การตอบกลับคำขอ

เมื่อมีคำขอเข้ามาใน Service Worker คุณสามารถดำเนินการได้ 2 อย่างคือ ไม่สนใจคำขอ จะทำให้ระบบส่งคำสั่งนั้นไปที่เครือข่าย หรือจะตอบกลับก็ได้ การตอบกลับคำขอจากภายใน Service Worker คือวิธีที่คุณสามารถเลือกสิ่งที่ทำได้และวิธีการส่งคืนไปยัง PWA ของคุณแม้ว่าผู้ใช้จะออฟไลน์อยู่ก็ตาม

หากต้องการตอบกลับคำขอที่เข้ามาใหม่ ให้โทรหา event.respondWith() จากภายในเครื่องจัดการเหตุการณ์ fetch ดังต่อไปนี้

// fetch event handler in your service worker file
self.addEventListener("fetch", event => {
    const response = .... // a response or a Promise of response
    event.respondWith(response);
});

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

การสร้างคำตอบ

คุณสามารถใช้ Fetch API เพื่อสร้างการตอบสนอง HTTP ในโค้ด JavaScript และสามารถแคชการตอบกลับเหล่านั้นโดยใช้ Cache Storage API และแสดงผลเหมือนกับว่ามาจากเว็บเซิร์ฟเวอร์

ในการสร้างคำตอบ ให้สร้างออบเจ็กต์ Response ใหม่ โดยตั้งค่าเนื้อความและตัวเลือกต่างๆ เช่น สถานะและส่วนหัว ดังนี้

const simpleResponse = new Response("Body of the HTTP response");

const options = {
   status: 200,
   headers: {
    'Content-type': 'text/html'
   }
};
const htmlResponse = new Response("<b>HTML</b> content", options)

การตอบกลับจากแคช

เมื่อคุณทราบวิธีแสดงการตอบกลับ HTTP จาก Service Worker แล้ว ก็ถึงเวลาใช้อินเทอร์เฟซการแคชพื้นที่เก็บข้อมูลเพื่อจัดเก็บเนื้อหาในอุปกรณ์

คุณสามารถใช้ Cache Storage API เพื่อตรวจสอบว่าคําขอที่ได้รับจาก PWA อยู่ในแคชหรือไม่ และหากมี ให้ตอบกลับ respondWith() โดยใช้คำขอดังกล่าว ในการทำเช่นนั้น คุณต้องค้นหาภายในแคชก่อน ฟังก์ชัน match() ซึ่งมีอยู่ที่อินเทอร์เฟซ caches ระดับบนสุดจะค้นหา Store ทั้งหมดในต้นทางหรือในออบเจ็กต์แคชที่เปิดอยู่รายการเดียว

ฟังก์ชัน match() ได้รับคำขอ HTTP หรือ URL เป็นอาร์กิวเมนต์ และแสดงผลสัญญาที่แปลงข้อมูลด้วยการตอบกลับที่เชื่อมโยงกับคีย์ที่เกี่ยวข้อง

// Global search on all caches in the current origin
caches.match(urlOrRequest).then(response => {
   console.log(response ? response : "It's not in the cache");
});

// Cache-specific search
caches.open("pwa-assets").then(cache => {
  cache.match(urlOrRequest).then(response => {
    console.log(response ? response : "It's not in the cache");
  });
});

กลยุทธ์การแคช

การแสดงไฟล์จากแคชของเบราว์เซอร์เท่านั้นไม่เหมาะกับกรณีการใช้งานทั้งหมด ตัวอย่างเช่น ผู้ใช้หรือเบราว์เซอร์สามารถนำแคชออกได้ คุณจึงควรกำหนดกลยุทธ์ในการส่งเนื้อหาสำหรับ PWA คุณไม่ได้ถูกจำกัดให้ใช้กลยุทธ์การแคชเพียงกลยุทธ์เดียว ให้กำหนด URL ที่แตกต่างกันสำหรับรูปแบบ URL ที่แตกต่างกัน ตัวอย่างเช่น คุณอาจมีกลยุทธ์หนึ่งสำหรับเนื้อหา UI ขั้นต่ำ อีกกลยุทธ์หนึ่งสำหรับการเรียก API และอีกกลยุทธ์หนึ่งสำหรับ URL รูปภาพและข้อมูล ในการดำเนินการนี้ ให้อ่าน event.request.url ใน ServiceWorkerGlobalScope.onfetch และแยกวิเคราะห์ผ่านนิพจน์ทั่วไปหรือรูปแบบ URL (ในขณะที่เขียน รูปแบบ URL ยังไม่ได้รับการสนับสนุนในบางแพลตฟอร์ม)

กลยุทธ์ที่ใช้กันมากที่สุด ได้แก่

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

แคชก่อน

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

กลยุทธ์ Cache First

self.addEventListener("fetch", event => {
   event.respondWith(
     caches.match(event.request)
     .then(cachedResponse => {
       // It can update the cache to serve updated content on the next request
         return cachedResponse || fetch(event.request);
     }
   )
  )
});

เครือข่ายก่อน

กลยุทธ์นี้เป็นการมิเรอร์ของกลยุทธ์ Cache First โดยจะตรวจสอบว่าสามารถดำเนินการตามคำขอจากเครือข่ายได้หรือไม่ และหากทำไม่ได้ จะลองเรียกข้อมูลจากแคช กดชอบแคชก่อน หากไม่มีการตอบสนองของเครือข่ายหรือการตอบสนองแคช คำขอจะเกิดข้อผิดพลาด การได้รับการตอบสนองจากเครือข่ายมักจะช้ากว่าการรับข้อมูลจากแคช กลยุทธ์นี้ให้ความสำคัญกับเนื้อหาที่อัปเดตมากกว่าประสิทธิภาพ

กลยุทธ์ Network First

self.addEventListener("fetch", event => {
   event.respondWith(
     fetch(event.request)
     .catch(error => {
       return caches.match(event.request) ;
     })
   );
});

ไม่มีอัปเดตขณะตรวจสอบความถูกต้องอีกครั้ง

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

ไม่มีอัปเดตขณะตรวจสอบความถูกต้องของกลยุทธ์อีกครั้ง

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request).then(cachedResponse => {
        const networkFetch = fetch(event.request).then(response => {
          // update the cache with a clone of the network response
          const responseClone = response.clone()
          caches.open(url.searchParams.get('name')).then(cache => {
            cache.put(event.request, responseClone)
          })
          return response
        }).catch(function (reason) {
          console.error('ServiceWorker fetch failed: ', reason)
        })
        // prioritize cached response over network
        return cachedResponse || networkFetch
      }
    )
  )
})

เครือข่ายเท่านั้น

กลยุทธ์แบบเครือข่ายเท่านั้นจะคล้ายกับลักษณะการทำงานของเบราว์เซอร์เมื่อใช้ Service Worker หรือ Cache Storage API คำขอจะส่งกลับทรัพยากรในกรณีที่ดึงข้อมูลจากเครือข่ายได้เท่านั้น วิธีนี้มีประโยชน์สำหรับทรัพยากรอย่างคำขอ API ทางออนไลน์เท่านั้น

กลยุทธ์ &quot;เครือข่ายเท่านั้น&quot;

แคชเท่านั้น

กลยุทธ์ที่ใช้แคชเท่านั้นช่วยให้แน่ใจว่าคำขอจะไม่ส่งไปที่เครือข่าย คำขอที่เข้ามาทั้งหมดจะได้รับการตอบสนองด้วยรายการแคชที่ป้อนข้อมูลไว้ล่วงหน้า โค้ดต่อไปนี้ใช้เครื่องจัดการเหตุการณ์ fetch กับเมธอด match ของพื้นที่เก็บข้อมูลแคชเพื่อตอบกลับแคชเท่านั้น

self.addEventListener("fetch", event => {
   event.respondWith(caches.match(event.request));
});

กลยุทธ์แคชเท่านั้น

กลยุทธ์ที่กำหนดเอง

แม้ว่าวิธีการข้างต้นจะเป็นกลยุทธ์การแคชที่พบได้ทั่วไป แต่คุณเป็นผู้รับผิดชอบ Service Worker และวิธีจัดการคำขอ หากไม่มีวิธีที่ตรงกับความต้องการของคุณเลย ให้สร้างขึ้นมา

เช่น คุณสามารถใช้กลยุทธ์แบบเครือข่ายเป็นหลักซึ่งมีระยะหมดเวลาเพื่อจัดลำดับความสำคัญของเนื้อหาที่อัปเดต แต่ใช้เฉพาะในกรณีที่การตอบกลับนั้นปรากฏในเกณฑ์ที่คุณตั้งไว้ นอกจากนี้คุณยังผสานการตอบกลับที่แคชไว้เข้ากับการตอบกลับของเครือข่ายและสร้างการตอบสนองที่ซับซ้อนจาก Service Worker ได้ด้วย

กำลังอัปเดตเนื้อหา

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

แหล่งข้อมูล