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

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

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

  • Chrome: 40
  • ขอบ: 17
  • Firefox: 44
  • Safari: 11.1

แหล่งที่มา

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

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

โปรแกรมทำงานของบริการจะอยู่ระหว่างไคลเอ็นต์กับเครือข่าย

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

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

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

เมื่อมีคำขอส่งมายังโปรแกรมทำงานของบริการ สิ่งที่ทำได้มี 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() ที่ได้รับการแก้ไขด้วยการตอบกลับได้

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

ด้วย 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 แล้ว ได้เวลาใช้อินเทอร์เฟซพื้นที่เก็บข้อมูลการแคชเพื่อจัดเก็บเนื้อหาไว้ในอุปกรณ์แล้ว

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

ฟังก์ชัน 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 คุณไม่ได้ถูกจำกัดเพียงแค่กลยุทธ์การแคช 1 กลยุทธ์ คุณสามารถกำหนดรูปแบบ 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 แบบออนไลน์เท่านั้น

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

แคชเท่านั้น

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

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

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

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

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

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

การอัปเดตเนื้อหา

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

แหล่งข้อมูล