ในปี 2015 เราได้เปิดตัวการซิงค์ข้อมูลในเบื้องหลัง ซึ่งช่วยให้ Service Worker เลื่อนงานออกไปจนกว่าผู้ใช้จะมีสัญญาณ ซึ่งหมายความว่าผู้ใช้สามารถพิมพ์ข้อความ กดส่ง และออกจากเว็บไซต์ได้โดยทราบว่าระบบจะส่งข้อความในตอนนี้หรือเมื่อผู้ใช้มีการเชื่อมต่อ
ฟีเจอร์นี้มีประโยชน์ แต่ต้องใช้ Service Worker ที่ทำงานอยู่ตลอดระยะเวลาของ การดึงข้อมูล ซึ่งจะไม่เป็นปัญหาสำหรับงานสั้นๆ เช่น การส่งข้อความ แต่หากงานใช้เวลานานเกินไป เบราว์เซอร์จะปิด Service Worker มิฉะนั้นจะเป็นความเสี่ยงต่อความเป็นส่วนตัวและแบตเตอรี่ของผู้ใช้
แล้วจะทำอย่างไรหากคุณต้องการดาวน์โหลดสิ่งที่อาจใช้เวลานาน เช่น ภาพยนตร์ พอดแคสต์ หรือ เลเวลของเกม การดึงข้อมูลในเบื้องหลังมีไว้เพื่อจุดประสงค์นี้
Background Fetch พร้อมใช้งานโดยค่าเริ่มต้นตั้งแต่ Chrome 74
นี่คือการสาธิตสั้นๆ 2 นาทีที่แสดงสถานะแบบเดิมๆ เทียบกับการใช้การดึงข้อมูลในเบื้องหลัง
วิธีการทำงาน
การดึงข้อมูลในเบื้องหลังจะทำงานดังนี้
- คุณบอกเบราว์เซอร์ให้ทำการดึงข้อมูลกลุ่มหนึ่งในเบื้องหลัง
- เบราว์เซอร์จะดึงข้อมูลเหล่านั้นและแสดงความคืบหน้าต่อผู้ใช้
- เมื่อการดึงข้อมูลเสร็จสมบูรณ์หรือล้มเหลว เบราว์เซอร์จะเปิด Service Worker และทริกเกอร์เหตุการณ์ เพื่อแจ้งให้คุณทราบสิ่งที่เกิดขึ้น ในส่วนนี้ คุณจะตัดสินใจได้ว่าจะทำอย่างไรกับคำตอบ (หากมี)
หากผู้ใช้ปิดหน้าเว็บของเว็บไซต์หลังจากขั้นตอนที่ 1 ก็ไม่เป็นไร การดาวน์โหลดจะดำเนินต่อไป เนื่องจาก การดึงข้อมูลมองเห็นได้ชัดเจนและยกเลิกได้ง่าย จึงไม่มีข้อกังวลด้านความเป็นส่วนตัวของงานซิงค์ข้อมูลในเบื้องหลังที่นานเกินไป เนื่องจาก Service Worker ไม่ได้ทำงานตลอดเวลา จึงไม่ต้องกังวลว่า Service Worker จะละเมิดระบบ เช่น ขุด Bitcoin ในเบื้องหลัง
ในบางแพลตฟอร์ม (เช่น Android) เบราว์เซอร์อาจปิดหลังจากขั้นตอนที่ 1 เนื่องจาก เบราว์เซอร์สามารถส่งต่อการดึงข้อมูลไปยังระบบปฏิบัติการได้
หากผู้ใช้เริ่มดาวน์โหลดขณะออฟไลน์หรือออฟไลน์ระหว่างการดาวน์โหลด ระบบจะหยุดการดึงข้อมูลในเบื้องหลังชั่วคราวและดำเนินการต่อในภายหลัง
API
ตรวจหาฟีเจอร์
เช่นเดียวกับฟีเจอร์ใหม่ๆ คุณต้องตรวจหาว่าเบราว์เซอร์รองรับฟีเจอร์นี้หรือไม่ สำหรับการดึงข้อมูลในเบื้องหลัง คุณทำได้ง่ายๆ ดังนี้
if ('BackgroundFetchManager' in self) {
// This browser supports Background Fetch!
}
การเริ่มดึงข้อมูลในเบื้องหลัง
API หลักจะเชื่อมต่อกับการลงทะเบียน Service Worker ดังนั้นโปรดตรวจสอบว่าคุณได้ลงทะเบียน Service Worker แล้ว จากนั้นให้ทำดังนี้
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch('my-fetch', ['/ep-5.mp3', 'ep-5-artwork.jpg'], {
title: 'Episode 5: Interesting things.',
icons: [{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
}],
downloadTotal: 60 * 1024 * 1024,
});
});
backgroundFetch.fetch
รับอาร์กิวเมนต์ 3 รายการ ได้แก่
พารามิเตอร์ | |
---|---|
id |
string ระบุการดึงข้อมูลในเบื้องหลังนี้อย่างไม่ซ้ำกัน
|
requests |
Array<Request|string>
สิ่งที่ต้องดึงข้อมูล ระบบจะถือว่าสตริงเป็น URL และเปลี่ยนเป็น Request ผ่าน new Request(theString)
คุณสามารถดึงข้อมูลจากต้นทางอื่นๆ ได้ตราบใดที่ทรัพยากรอนุญาตผ่าน CORS หมายเหตุ: ขณะนี้ Chrome ยังไม่รองรับคำขอที่ต้องมีการตรวจสอบเบื้องต้นของ CORS |
options |
ออบเจ็กต์ซึ่งอาจรวมถึงข้อมูลต่อไปนี้ |
options.title |
string ชื่อสำหรับเบราว์เซอร์เพื่อแสดงพร้อมกับความคืบหน้า |
options.icons |
Array<IconDefinition> อาร์เรย์ของออบเจ็กต์ที่มี `src`, `size` และ `type` |
options.downloadTotal |
number ขนาดทั้งหมดของเนื้อหาการตอบกลับ (หลังจากยกเลิกการบีบอัดด้วย gzip) แม้ว่าคุณจะระบุหรือไม่ก็ได้ แต่เราขอแนะนำเป็นอย่างยิ่งให้ระบุ โดยใช้เพื่อแจ้งให้ผู้ใช้ทราบขนาดการดาวน์โหลดและแสดงข้อมูลความคืบหน้า หากไม่ระบุข้อมูลนี้ เบราว์เซอร์จะแจ้งให้ผู้ใช้ทราบว่าไม่ทราบขนาด และผู้ใช้อาจมีแนวโน้มที่จะยกเลิกการดาวน์โหลดมากขึ้น หากการดึงข้อมูลในเบื้องหลังดาวน์โหลดเกินจำนวนที่ระบุไว้ที่นี่ ระบบจะยกเลิกการดึงข้อมูล |
backgroundFetch.fetch
จะแสดงผล Promise ที่แก้ไขด้วย BackgroundFetchRegistration
ฉันจะ
อธิบายรายละเอียดในภายหลัง Promise จะปฏิเสธหากผู้ใช้เลือกไม่ใช้การดาวน์โหลด หรือพารามิเตอร์ที่ระบุอย่างน้อย 1 รายการไม่ถูกต้อง
การระบุคำขอจำนวนมากสำหรับการดึงข้อมูลในเบื้องหลังรายการเดียวช่วยให้คุณรวมรายการต่างๆ ที่เป็นรายการเดียวเชิงตรรกะสำหรับผู้ใช้ได้ เช่น ภาพยนตร์อาจแบ่งออกเป็นแหล่งข้อมูลหลายพันรายการ (โดยทั่วไปจะใช้ MPEG-DASH) และมาพร้อมกับแหล่งข้อมูลเพิ่มเติม เช่น รูปภาพ เลเวลของเกมอาจกระจายอยู่ตามทรัพยากร JavaScript, รูปภาพ และเสียงจำนวนมาก แต่สำหรับผู้ใช้แล้ว มันก็คือ "ภาพยนตร์" หรือ "เลเวล"
การรับการดึงข้อมูลในเบื้องหลังที่มีอยู่
คุณสามารถรับการดึงข้อมูลในเบื้องหลังที่มีอยู่ได้ดังนี้
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});
…โดยส่ง id ของการดึงข้อมูลในเบื้องหลังที่ต้องการ get
จะแสดงผล undefined
หากไม่มีการดึงข้อมูลในเบื้องหลังที่ใช้งานอยู่ซึ่งมีรหัสดังกล่าว
ระบบจะถือว่าการดึงข้อมูลในเบื้องหลัง "ทำงานอยู่" ตั้งแต่เวลาที่ลงทะเบียนจนกว่าจะสำเร็จ ล้มเหลว หรือถูกยกเลิก
คุณดูรายการการดึงข้อมูลในเบื้องหลังที่ใช้งานอยู่ทั้งหมดได้โดยใช้ getIds
navigator.serviceWorker.ready.then(async (swReg) => {
const ids = await swReg.backgroundFetch.getIds();
});
การลงทะเบียนการดึงข้อมูลในเบื้องหลัง
BackgroundFetchRegistration
(bgFetch
ในตัวอย่างด้านบน) มีลักษณะดังนี้
พร็อพเพอร์ตี้ | |
---|---|
id |
string รหัสของการดึงข้อมูลในเบื้องหลัง |
uploadTotal |
number จำนวนไบต์ที่จะส่งไปยังเซิร์ฟเวอร์ |
uploaded |
number จำนวนไบต์ที่ส่งสำเร็จ |
downloadTotal |
number ค่าที่ระบุเมื่อลงทะเบียนการดึงข้อมูลในเบื้องหลัง หรือ 0 |
downloaded |
number จำนวนไบต์ที่ได้รับสำเร็จ ค่านี้อาจลดลง เช่น หากการเชื่อมต่อขาดหายไปและดาวน์โหลดต่อไม่ได้ ในกรณีนี้ เบราว์เซอร์จะรีสตาร์ทการดึงข้อมูลสำหรับทรัพยากรนั้นตั้งแต่ต้น |
result |
ประเภทใดประเภทหนึ่งต่อไปนี้
|
failureReason |
ประเภทใดประเภทหนึ่งต่อไปนี้
|
recordsAvailable |
boolean เข้าถึงคำขอ/การตอบกลับที่เกี่ยวข้องได้ไหม เมื่อตั้งค่าเป็นเท็จแล้ว คุณจะใช้ |
เมธอด | |
abort() |
ส่งคืน Promise<boolean> ยกเลิกการดึงข้อมูลในเบื้องหลัง Promise ที่ส่งคืนจะได้รับการแก้ไขเป็นจริงหากยกเลิกการดึงข้อมูลสำเร็จ |
matchAll(request, opts) |
การคืนสินค้า Promise<Array<BackgroundFetchRecord>> รับคำขอ และการตอบกลับ อาร์กิวเมนต์ในที่นี้เหมือนกับ API ของแคช การเรียกใช้โดยไม่มีอาร์กิวเมนต์จะแสดงผล Promise สำหรับระเบียนทั้งหมด ดูรายละเอียดเพิ่มเติมด้านล่าง |
match(request, opts) |
แสดงผล Promise<BackgroundFetchRecord> เช่นเดียวกับด้านบน แต่จะแสดงผล รายการแรกที่ตรงกัน |
กิจกรรม | |
progress |
ทริกเกอร์เมื่อ uploaded , downloaded , result หรือ
failureReason มีการเปลี่ยนแปลง |
การติดตามความคืบหน้า
ซึ่งทำได้ผ่านเหตุการณ์ progress
โปรดทราบว่า downloadTotal
คือค่าที่คุณระบุ หรือ 0
หากคุณไม่ได้ระบุค่า
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(bgFetch.downloaded / bgFetch.downloadTotal * 100);
console.log(`Download progress: ${percent}%`);
});
การรับคำขอและการตอบกลับ
bgFetch.match('/ep-5.mp3').then(async (record) => {
if (!record) {
console.log('No record found');
return;
}
console.log(`Here's the request`, record.request);
const response = await record.responseReady;
console.log(`And here's the response`, response);
});
record
คือ BackgroundFetchRecord
และมีลักษณะดังนี้
พร็อพเพอร์ตี้ | |
---|---|
request |
Request คำขอที่ระบุ |
responseReady |
Promise<Response> คำตอบที่ดึงข้อมูล การตอบกลับอยู่เบื้องหลัง Promise เนื่องจากอาจยังไม่ได้รับ สัญญา จะปฏิเสธหากการดึงข้อมูลล้มเหลว |
เหตุการณ์ของ Service Worker
กิจกรรม | |
---|---|
backgroundfetchsuccess |
ดึงข้อมูลทุกอย่างเรียบร้อยแล้ว |
backgroundfetchfailure |
การดึงข้อมูลอย่างน้อย 1 รายการไม่สำเร็จ |
backgroundfetchabort |
การดึงข้อมูลอย่างน้อย 1 รายการล้มเหลว
ซึ่งจะมีประโยชน์ก็ต่อเมื่อคุณต้องการล้างข้อมูลที่เกี่ยวข้อง |
backgroundfetchclick |
ผู้ใช้คลิก UI ความคืบหน้าในการดาวน์โหลด |
ออบเจ็กต์เหตุการณ์มีข้อมูลต่อไปนี้
พร็อพเพอร์ตี้ | |
---|---|
registration |
BackgroundFetchRegistration |
เมธอด | |
updateUI({ title, icons }) |
ให้คุณเปลี่ยนชื่อ/ไอคอนที่ตั้งค่าไว้ตอนแรก โดยคุณจะดำเนินการตามขั้นตอนนี้หรือไม่ก็ได้ แต่จะช่วยให้คุณ
ให้บริบทเพิ่มเติมได้หากจำเป็น คุณจะดำเนินการนี้ได้เพียง *ครั้งเดียว* ในช่วง
กิจกรรม backgroundfetchsuccess และ backgroundfetchfailure |
การตอบสนองต่อความสำเร็จ/ความล้มเหลว
เราเห็นเหตุการณ์ progress
แล้ว แต่เหตุการณ์นี้จะมีประโยชน์เฉพาะในขณะที่ผู้ใช้เปิดหน้าเว็บของ
เว็บไซต์ของคุณ ประโยชน์หลักของการดึงข้อมูลเบื้องหลังคือสิ่งต่างๆ จะยังคงทำงานต่อไปหลังจากที่ผู้ใช้ออกจากหน้าเว็บ หรือแม้กระทั่งปิดเบราว์เซอร์
หากการดึงข้อมูลในเบื้องหลังเสร็จสมบูรณ์ Service Worker จะได้รับเหตุการณ์
backgroundfetchsuccess
และ event.registration
จะเป็นการลงทะเบียนการดึงข้อมูลในเบื้องหลัง
หลังจากเหตุการณ์นี้ คุณจะเข้าถึงคำขอและการตอบกลับที่ดึงมาไม่ได้อีกต่อไป ดังนั้นหากต้องการเก็บไว้ ให้ย้ายไปที่อื่น เช่น Cache API
เช่นเดียวกับเหตุการณ์ Service Worker ส่วนใหญ่ ให้ใช้ event.waitUntil
เพื่อให้ Service Worker ทราบเมื่อเหตุการณ์
เสร็จสมบูรณ์
ตัวอย่างเช่น ใน Service Worker
addEventListener('backgroundfetchsuccess', (event) => {
const bgFetch = event.registration;
event.waitUntil(async function() {
// Create/open a cache.
const cache = await caches.open('downloads');
// Get all the records.
const records = await bgFetch.matchAll();
// Copy each request/response across.
const promises = records.map(async (record) => {
const response = await record.responseReady;
await cache.put(record.request, response);
});
// Wait for the copying to complete.
await Promise.all(promises);
// Update the progress notification.
event.updateUI({ title: 'Episode 5 ready to listen!' });
}());
});
ความล้มเหลวอาจเกิดจากข้อผิดพลาด 404 เพียงรายการเดียว ซึ่งอาจไม่สำคัญสำหรับคุณ ดังนั้นจึงอาจยังคุ้มค่าที่จะคัดลอกการตอบกลับบางรายการลงในแคชตามที่ระบุไว้ข้างต้น
การตอบสนองต่อการคลิก
UI ที่แสดงความคืบหน้าและผลลัพธ์ของการดาวน์โหลดจะคลิกได้ backgroundfetchclick
เหตุการณ์ใน
Service Worker ช่วยให้คุณตอบสนองต่อเหตุการณ์นี้ได้ ตามที่กล่าวข้างต้น event.registration
จะเป็นการลงทะเบียนการดึงข้อมูลในเบื้องหลัง
โดยปกติแล้วเมื่อเกิดเหตุการณ์นี้จะมีการเปิดหน้าต่าง
addEventListener('backgroundfetchclick', (event) => {
const bgFetch = event.registration;
if (bgFetch.result === 'success') {
clients.openWindow('/latest-podcasts');
} else {
clients.openWindow('/download-progress');
}
});
แหล่งข้อมูลเพิ่มเติม
การแก้ไข: บทความเวอร์ชันก่อนหน้านี้อ้างถึง Background Fetch ว่าเป็น "มาตรฐานเว็บ" อย่างไม่ถูกต้อง ขณะนี้ API ยังไม่ได้อยู่ในเส้นทางมาตรฐาน และข้อกำหนดอยู่ใน WICG ในรูปแบบรายงานฉบับร่างของกลุ่มชุมชน