ในปี 2015 เราได้เปิดตัวการซิงค์ในเบื้องหลัง ซึ่งช่วยให้ Service Worker เลื่อนการทำงานจนกว่าผู้ใช้จะมีการเชื่อมต่อ ซึ่งหมายความว่าผู้ใช้สามารถพิมพ์ข้อความ กดส่ง แล้วออกจากเว็บไซต์ได้ โดยที่ระบบจะส่งข้อความให้ทันทีหรือเมื่อผู้ใช้มีการเชื่อมต่อ
ฟีเจอร์นี้มีประโยชน์ แต่กำหนดให้ Service Worker ทำงานอยู่ตลอดระยะเวลาการดึงข้อมูล ซึ่งไม่มีปัญหาสำหรับงานสั้นๆ เช่น การส่งข้อความ แต่หากงานใช้เวลานานเกินไป เบราว์เซอร์จะหยุด Service Worker ดังกล่าว มิเช่นนั้นจะเป็นอันตรายต่อความเป็นส่วนตัวและแบตเตอรี่ของผู้ใช้
ในกรณีที่คุณต้องดาวน์โหลดเนื้อหาที่อาจใช้เวลานาน เช่น ภาพยนตร์ พอดแคสต์ หรือด่านของเกม ซึ่งเป็นหน้าที่ของการดึงข้อมูลในเบื้องหลัง
การดึงข้อมูลในเบื้องหลังพร้อมใช้งานโดยค่าเริ่มต้นตั้งแต่ Chrome 74
ลองดูการสาธิตสั้นๆ 2 นาทีนี้ที่แสดงสถานะแบบดั้งเดิมเทียบกับการใช้การดึงข้อมูลเบื้องหลัง
ลองใช้การสาธิตด้วยตัวคุณเองและเรียกดูโค้ด
วิธีการทำงาน
การดึงข้อมูลในเบื้องหลังมีลักษณะดังนี้
- คุณบอกให้เบราว์เซอร์ดึงข้อมูลกลุ่มในเบื้องหลัง
- จากนั้นเบราว์เซอร์จะดึงข้อมูลเหล่านั้นมาแสดงความคืบหน้าต่อผู้ใช้
- เมื่อการดึงข้อมูลเสร็จสมบูรณ์หรือล้มเหลว เบราว์เซอร์จะเปิด Service Worker และเริ่มการทำงานของเหตุการณ์เพื่อบอกคุณว่าเกิดอะไรขึ้น ในส่วนนี้ คุณเลือกได้ว่าจะทำอย่างไรกับคำตอบ (หากมี)
หากผู้ใช้ปิดหน้าเว็บในเว็บไซต์ของคุณหลังจากขั้นตอนที่ 1 ก็ไม่เป็นไร การดาวน์โหลดจะยังคงดำเนินต่อไป เนื่องจากการดึงข้อมูลนั้นสังเกตเห็นได้ชัดเจนและหยุดได้ง่าย จึงไม่ต้องกังวลเรื่องความเป็นส่วนตัวของงานซิงค์ในเบื้องหลังที่ใช้เวลานานเกินไป เนื่องจาก 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 Preflight |
options |
ออบเจ็กต์ที่อาจประกอบด้วยข้อมูลต่อไปนี้ |
options.title |
string ชื่อสำหรับเบราว์เซอร์ที่จะแสดงพร้อมกับความคืบหน้า |
options.icons |
Array<IconDefinition> อาร์เรย์ของออบเจ็กต์ที่มี "src" "size" และ "type" |
options.downloadTotal |
number ขนาดโดยรวมของเนื้อหาการตอบกลับ (หลังจากคลาย gzip) แม้ว่าจะไม่ใช่ข้อมูลที่ต้องระบุ แต่เราขอแนะนําอย่างยิ่งให้คุณระบุข้อมูลนี้ ใช้เพื่อบอกให้ผู้ใช้ทราบถึงขนาดของการดาวน์โหลดและเพื่อให้ข้อมูลความคืบหน้า หากคุณไม่ได้ระบุค่านี้ เบราว์เซอร์จะแจ้งให้ผู้ใช้ทราบว่าไม่ทราบขนาด ซึ่งอาจทำให้ผู้ใช้มีแนวโน้มที่จะยกเลิกการดาวน์โหลด หากการดาวน์โหลดจากการดึงข้อมูลในเบื้องหลังมีจำนวนมากกว่าที่ระบุไว้ที่นี่ ระบบจะยกเลิกการดึงข้อมูล ไม่เป็นไรหากการดาวน์โหลดมีขนาดเล็กกว่า |
backgroundFetch.fetch
แสดงผลพรอมต์ที่แสดงผลเป็น BackgroundFetchRegistration
เราจะอธิบายรายละเอียดในภายหลัง สัญญาจะปฏิเสธหากผู้ใช้เลือกไม่ใช้การดาวน์โหลด หรือพารามิเตอร์ใดพารามิเตอร์หนึ่งที่ระบุไม่ถูกต้อง
การส่งคําขอหลายรายการสําหรับการดึงข้อมูลเบื้องหลังครั้งเดียวช่วยให้คุณรวมสิ่งที่เป็นสิ่งเดียวกันสําหรับผู้ใช้ได้ ตัวอย่างเช่น ภาพยนตร์อาจแบ่งออกเป็นทรัพยากรหลายพันรายการ (โดยทั่วไปจะใช้กับ 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 การเรียกใช้โดยไม่มีอาร์กิวเมนต์จะแสดงผลลัพธ์เป็นสัญญาสำหรับระเบียนทั้งหมด ดูรายละเอียดเพิ่มเติมด้านล่าง |
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> คำตอบที่ดึงข้อมูล การตอบกลับอยู่หลังการสัญญาเนื่องจากอาจยังไม่ได้รับ สัญญาจะปฏิเสธหากดึงข้อมูลไม่สำเร็จ |
เหตุการณ์ Service Worker
เหตุการณ์ | |
---|---|
backgroundfetchsuccess |
ดึงข้อมูลทั้งหมดเรียบร้อยแล้ว |
backgroundfetchfailure |
การเรียกข้อมูลล้มเหลวอย่างน้อย 1 รายการ |
backgroundfetchabort |
ดึงข้อมูลไม่สำเร็จอย่างน้อย 1 รายการ
ซึ่งจะมีประโยชน์ก็ต่อเมื่อคุณต้องการล้างข้อมูลที่เกี่ยวข้องเท่านั้น |
backgroundfetchclick |
ผู้ใช้คลิก UI ความคืบหน้าการดาวน์โหลด |
ออบเจ็กต์เหตุการณ์มีข้อมูลต่อไปนี้
พร็อพเพอร์ตี้ | |
---|---|
registration |
BackgroundFetchRegistration |
เมธอด | |
updateUI({ title, icons }) |
ให้คุณเปลี่ยนชื่อ/ไอคอนที่ตั้งไว้ตั้งแต่แรก คุณจะระบุหรือไม่ก็ได้ แต่จะช่วยให้คุณระบุบริบทเพิ่มเติมได้หากจําเป็น คุณดำเนินการนี้ได้ *1 ครั้ง* เท่านั้นในระหว่างกิจกรรม backgroundfetchsuccess และ backgroundfetchfailure |
การตอบสนองต่อความสำเร็จ/ความล้มเหลว
เราเห็นเหตุการณ์ progress
แล้ว แต่เหตุการณ์นี้จะมีประโยชน์ก็ต่อเมื่อผู้ใช้เปิดหน้าเว็บในเว็บไซต์ของคุณอยู่เท่านั้น ประโยชน์หลักของการดึงข้อมูลในเบื้องหลังคือระบบจะดึงข้อมูลต่อไปหลังจากที่ผู้ใช้ออกจากหน้าเว็บหรือปิดเบราว์เซอร์
หากการดึงข้อมูลในเบื้องหลังเสร็จสมบูรณ์ บริการเวิร์กเกอร์ของคุณจะได้รับเหตุการณ์ backgroundfetchsuccess
และ event.registration
จะเป็นการลงชื่อสมัครใช้การดึงข้อมูลในเบื้องหลัง
หลังจากเหตุการณ์นี้ คุณจะไม่เข้าถึงคำขอและคำตอบที่ดึงข้อมูลไว้ได้อีกต่อไป ดังนั้นหากต้องการเก็บไว้ ให้ย้ายคำขอและคำตอบดังกล่าวไปยังที่อื่น เช่น แคช 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');
}
});
แหล่งข้อมูลเพิ่มเติม
การแก้ไข: บทความเวอร์ชันก่อนหน้าเรียกการดึงข้อมูลในเบื้องหลังอย่างไม่ถูกต้องว่าเป็น "มาตรฐานเว็บ" ปัจจุบัน API นี้ไม่ได้อยู่ในมาตรฐาน คุณสามารถดูข้อกําหนดได้ใน WICG เป็นรายงานฉบับร่างของกลุ่มชุมชน