ในปี 2015 เราได้เปิดตัวการซิงค์ในเบื้องหลัง ซึ่งช่วยให้โปรแกรมทำงานของบริการเลื่อนการทำงานไปจนกว่าผู้ใช้จะมีการเชื่อมต่อ ซึ่งหมายความว่าผู้ใช้จะพิมพ์ข้อความ กดส่ง และออกจากเว็บไซต์โดยทราบว่าระบบจะส่งข้อความตอนนี้หรือเมื่อมีการเชื่อมต่อ
นี่เป็นฟีเจอร์ที่มีประโยชน์ แต่ Service Worker จะต้องยังไม่ทำงานในช่วงที่ดึงข้อมูล นั่นไม่ใช่ปัญหาสำหรับงานเล็กๆ น้อยๆ เช่น การส่งข้อความ แต่หากงานนั้นใช้เวลานานเกินไป เบราว์เซอร์จะทำให้โปรแกรมทำงานของบริการหยุดชะงัก หรือมีความเสี่ยงต่อความเป็นส่วนตัวของผู้ใช้และแบตเตอรี่
สรุปคือถ้าคุณต้องดาวน์โหลดเนื้อหาที่อาจต้องใช้เวลานานๆ เช่น ภาพยนตร์ พอดแคสต์ หรือด่านในเกม จึงเป็นวัตถุประสงค์ของการดึงข้อมูลในเบื้องหลัง
การดึงข้อมูลในเบื้องหลังพร้อมใช้งานโดยค่าเริ่มต้นตั้งแต่ Chrome 74 เป็นต้นไป
นี่เป็นการสาธิตสั้นๆ สองนาทีซึ่งแสดงสถานะดั้งเดิมของสิ่งต่างๆ เทียบกับการใช้การดึงข้อมูลในเบื้องหลัง:
ทดลองการสาธิตด้วยตัวเองและเรียกดูโค้ด
วิธีการทำงาน
การดึงข้อมูลในเบื้องหลังมีลักษณะการทำงานดังนี้
- คุณบอกให้เบราว์เซอร์ดำเนินการกลุ่มการดึงข้อมูลในเบื้องหลัง
- เบราว์เซอร์จะดึงข้อมูลเหล่านั้นและแสดงความคืบหน้าให้ผู้ใช้เห็น
- เมื่อการดึงข้อมูลเสร็จสมบูรณ์หรือล้มเหลว เบราว์เซอร์จะเปิด Service Worker และเริ่มการทำงานของเหตุการณ์เพื่อบอกคุณว่าเกิดอะไรขึ้น ในส่วนนี้ คุณจะเป็นผู้ตัดสินใจว่าจะดำเนินการอย่างไรกับคำตอบดังกล่าว (หากมี)
หากผู้ใช้ปิดหน้าต่างๆ ที่มายังเว็บไซต์ของคุณหลังจากขั้นตอนที่ 1 ไม่มีปัญหา การดาวน์โหลดจะดำเนินต่อไป เนื่องจากการดึงข้อมูลเป็นสิ่งสำคัญและจะยกเลิกได้ง่าย การซิงค์ในเบื้องหลังที่ใช้เวลานานเกินไปจึงไม่ใช่ข้อกังวลด้านความเป็นส่วนตัว เนื่องจากโปรแกรมทำงานของบริการไม่ได้ทำงานตลอดเวลา จึงไม่มีข้อกังวลว่าอาจละเมิดระบบ เช่น การขุดบิตคอยน์ในพื้นหลัง
ในบางแพลตฟอร์ม (เช่น Android) เบราว์เซอร์อาจปิดหลังขั้นตอนที่ 1 เนื่องจากเบราว์เซอร์สามารถส่งการดึงข้อมูลไปยังระบบปฏิบัติการ
หากผู้ใช้เริ่มการดาวน์โหลดขณะออฟไลน์หรือออฟไลน์ในระหว่างการดาวน์โหลด การดึงข้อมูลในเบื้องหลังจะหยุดชั่วคราวและกลับมาทำงานอีกครั้งในภายหลัง
API
การตรวจหาฟีเจอร์
คุณต้องตรวจสอบว่าเบราว์เซอร์รองรับหรือไม่ เช่นเดียวกับฟีเจอร์ใหม่อื่นๆ สำหรับการดึงข้อมูลในเบื้องหลังนั้น ง่ายมาก เช่น
if ('BackgroundFetchManager' in self) {
// This browser supports Background Fetch!
}
กำลังเริ่มดึงข้อมูลในเบื้องหลัง
API หลักจะทำให้การลงทะเบียนโปรแกรมทำงานของบริการหยุดลง ดังนั้นโปรดตรวจสอบว่าคุณได้ลงทะเบียนโปรแกรมทำงานของบริการก่อน จากนั้นให้ทำดังนี้
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 ขนาดโดยรวมของเนื้อหาการตอบกลับ (หลังจากยกเลิกการบีบอัด) แม้ว่าจะไม่บังคับ แต่เราขอแนะนำให้คุณระบุไว้ ใช้เพื่อบอกผู้ใช้ว่าการดาวน์โหลดมีขนาดใหญ่เพียงใดและเพื่อให้ข้อมูลความคืบหน้า หากคุณไม่ให้ข้อมูลนี้ เบราว์เซอร์จะแจ้งให้ผู้ใช้ทราบว่าไม่ทราบขนาด ซึ่งส่งผลให้ผู้ใช้มีแนวโน้มที่จะล้มเลิกการดาวน์โหลดมากขึ้น หากการดาวน์โหลดข้อมูลในเบื้องหลังเกินจำนวนที่ระบุไว้ที่นี่ ระบบจะยกเลิกการดาวน์โหลดดังกล่าว ไม่ต้องกังวลหากการดาวน์โหลดมีขนาดเล็กกว่า |
backgroundFetch.fetch
จะแสดงสัญญาที่แปลงด้วย BackgroundFetchRegistration
ฉันจะอธิบายรายละเอียด
ของเรื่องนั้นในภายหลัง สัญญาจะปฏิเสธหากผู้ใช้เลือกไม่รับการดาวน์โหลดหรือพารามิเตอร์รายการใดรายการหนึ่งที่ระบุไม่ถูกต้อง
การระบุคำขอจำนวนมากสำหรับการดึงข้อมูลพื้นหลังรายการเดียวจะทำให้คุณรวมสิ่งต่างๆ ที่มีเหตุผลเป็นสิ่งเดียวสำหรับผู้ใช้ได้ ตัวอย่างเช่น ภาพยนตร์อาจแบ่งออกเป็นทรัพยากรจำนวน 1,000 รายการ (โดยทั่วไปจะใช้ 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> ล้มเลิกการดึงข้อมูลในเบื้องหลัง หากล้มเลิกการดึงข้อมูลสำเร็จ ระบบจะแปลงข้อมูลที่แสดงผลเป็น "จริง" |
matchAll(request, opts) |
แสดงผล Promise<Array<BackgroundFetchRecord>> รับคำขอและการตอบกลับ โดยอาร์กิวเมนต์นี้จะเหมือนกับ Cache 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 }) |
ช่วยให้คุณสามารถเปลี่ยนชื่อ/ไอคอนที่ตั้งค่าไว้ในตอนแรกได้ ขั้นตอนนี้เป็นขั้นตอนที่ไม่บังคับ แต่ช่วยให้คุณให้บริบทเพิ่มเติมหากจำเป็น คุณสามารถทำเช่นนี้ได้เพียง *ครั้งเดียว* ในระหว่างกิจกรรม backgroundfetchsuccess และ backgroundfetchfailure |
การตอบสนองต่อความสำเร็จ/ความล้มเหลว
เราได้เห็นเหตุการณ์ progress
ไปแล้ว แต่จะมีประโยชน์ก็ต่อเมื่อผู้ใช้เปิดหน้าเว็บบนเว็บไซต์ไว้ ประโยชน์หลักของการดึงข้อมูลในเบื้องหลังคือสิ่งต่างๆ จะยังทำงานต่อไปหลังจากที่ผู้ใช้ออกจากหน้าเว็บหรือแม้กระทั่งปิดเบราว์เซอร์
หากการดึงข้อมูลในเบื้องหลังเสร็จสมบูรณ์แล้ว Service Worker จะได้รับเหตุการณ์ backgroundfetchsuccess
และ event.registration
จะเป็นการลงทะเบียนการดึงข้อมูลในเบื้องหลัง
หลังเหตุการณ์นี้ คำขอและคำตอบที่ดึงมาจะเข้าถึงไม่ได้อีกต่อไป ดังนั้นหากต้องการเก็บไว้ ให้ย้ายไปที่ตำแหน่งอื่น เช่น cache API
เช่นเดียวกับเหตุการณ์ของ Service Worker ส่วนใหญ่ ให้ใช้ event.waitUntil
เพื่อให้โปรแกรมทำงานของบริการทราบเมื่อเหตุการณ์เสร็จสมบูรณ์
ตัวอย่างเช่น ใน 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 อาจเกิดจากข้อผิดพลาด 404 รายการซึ่งอาจไม่สำคัญสำหรับคุณ จึงควรคัดลอกคำตอบลงในแคชข้างต้น
การโต้ตอบเพื่อคลิก
UI ที่แสดงความคืบหน้าในการดาวน์โหลดและผลการค้นหาเป็นแบบคลิกได้ เหตุการณ์ backgroundfetchclick
ในโปรแกรมทำงานของบริการให้คุณโต้ตอบกับสิ่งนี้ได้ เช่นเดียวกับด้านบน event.registration
จะเป็นการลงทะเบียน
การดึงข้อมูลในเบื้องหลัง
โดยทั่วไปแล้ว กิจกรรมนี้คือการเปิดหน้าต่าง
addEventListener('backgroundfetchclick', (event) => {
const bgFetch = event.registration;
if (bgFetch.result === 'success') {
clients.openWindow('/latest-podcasts');
} else {
clients.openWindow('/download-progress');
}
});
แหล่งข้อมูลเพิ่มเติม
การแก้ไข: เวอร์ชันก่อนหน้าของบทความนี้เรียกอย่างไม่ถูกต้องว่าการดึงข้อมูลในเบื้องหลังว่าเป็น "มาตรฐานเว็บ" ขณะนี้ API ไม่ได้อยู่ในแทร็กมาตรฐาน ดูข้อกําหนดได้ใน WICG ในรูปแบบรายงานกลุ่มชุมชนฉบับร่าง