แง่มุมสำคัญของ Progressive Web App คือเชื่อถือได้ ทำให้โหลดเนื้อหาได้รวดเร็ว ทำให้ผู้ใช้มีส่วนร่วมอยู่เสมอและแสดงความคิดเห็นได้ทันที แม้เครือข่ายจะมีสภาวะไม่เสถียร เป็นไปได้อย่างไรน่ะหรือ ขอขอบคุณเหตุการณ์ fetch
ของ Service Worker
เหตุการณ์การดึงข้อมูล
เหตุการณ์ 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)
กลยุทธ์ที่ใช้กันมากที่สุด ได้แก่
- แคชก่อน
- ค้นหาการตอบกลับที่แคชไว้ก่อนแล้วจึงกลับไปที่เครือข่ายหากไม่พบ
- เครือข่ายก่อน
- ขอการตอบกลับจากเครือข่ายก่อนและหากไม่มีการส่งคืน ให้ตรวจสอบการตอบกลับในแคช
- ไม่มีอัปเดตขณะตรวจสอบความถูกต้องอีกครั้ง
- แสดงการตอบกลับจากแคชขณะที่อยู่เบื้องหลังจะขอเวอร์ชันล่าสุดและบันทึกลงในแคชเมื่อมีการขอเนื้อหาในครั้งถัดไป
- เครือข่ายเท่านั้น
- ตอบกลับด้วยการตอบกลับจากเครือข่ายเสมอหรือแจ้งข้อผิดพลาดออกมา ระบบจะไม่ศึกษาแคช
- แคชเท่านั้น
- ตอบกลับด้วยการตอบกลับจากแคชเสมอหรือตอบกลับจากข้อผิดพลาดเสมอ จะไม่มีการปรึกษาเครือข่ายโดยเด็ดขาด ต้องเพิ่มเนื้อหาที่จะแสดงโดยใช้กลยุทธ์นี้ลงในแคชก่อนที่จะขอ
แคชก่อน
เมื่อใช้กลยุทธ์นี้ โปรแกรมทำงานของบริการจะมองหาคำขอที่ตรงกันในแคช และแสดงผลการตอบกลับที่เกี่ยวข้องหากมีการแคชไว้ มิฉะนั้น ระบบจะเรียกคืนการตอบกลับจากเครือข่าย (หรือจะอัปเดตแคชสำหรับการเรียกในอนาคต) หากไม่มีทั้งการตอบสนองของแคชหรือการตอบสนองของเครือข่าย คำขอจะเกิดข้อผิดพลาด เนื่องจากการแสดงชิ้นงานโดยไม่ต้องเชื่อมต่อเครือข่ายมีแนวโน้มที่จะทําได้เร็วกว่า กลยุทธ์นี้จึงให้ความสำคัญกับประสิทธิภาพมากกว่าความใหม่
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 อุปกรณ์จะตรวจสอบว่าคำขอสามารถดำเนินการตามคำขอจากเครือข่ายได้หรือไม่ และหากทำไม่ได้ ก็จะพยายามเรียกข้อมูลจากแคช ชอบแคชก่อน ถ้าไม่มีการตอบสนองของเครือข่ายหรือแคช คำขอจะเกิดข้อผิดพลาด การได้รับการตอบสนองจากเครือข่ายมักจะช้ากว่าการรับจากแคช กลยุทธ์นี้ให้ความสำคัญกับเนื้อหาที่อัปเดตแล้วมากกว่าประสิทธิภาพ
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 ให้เป็นข้อมูลล่าสุดอาจเป็นเรื่องท้าทาย กลยุทธ์ที่ไม่มีการอัปเดตขณะตรวจสอบกลยุทธ์อีกครั้งเป็นวิธีหนึ่งที่สามารถทำได้ แต่นี่ไม่ใช่เพียงวิธีเดียว ในส่วนเนื้อหาอัปเดต คุณจะได้เรียนรู้เทคนิคต่าง ๆ ในการอัปเดตเนื้อหาและเนื้อหาของแอปอยู่เสมอ