workbox-background-sync

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

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

Workbox Background Sync ได้รับการออกแบบมาเพื่อใช้ BackgroundSync API ได้ง่ายขึ้นและผสานรวมการใช้งานกับโมดูล Workbox อื่นๆ รวมถึงใช้กลยุทธ์สำรองสำหรับเบราว์เซอร์ที่ยังไม่ได้ใช้ BackgroundSync ด้วย

เบราว์เซอร์ที่รองรับ BackgroundSync API จะเล่นคำขอที่ล้มเหลวซ้ำโดยอัตโนมัติในนามของคุณในช่วงเวลาที่เบราว์เซอร์จัดการ โดยมีแนวโน้มที่จะใช้การย้อนกลับแบบทวีคูณระหว่างการพยายามเล่นซ้ำ ในเบราว์เซอร์ที่ไม่รองรับ BackgroundSync API แล้ว Workbox Background Sync จะพยายามเล่นซ้ำโดยอัตโนมัติทุกครั้งที่ Service Worker เริ่มทำงาน

การใช้งานพื้นฐาน

วิธีที่ง่ายที่สุดในการใช้การซิงค์ในเบื้องหลังคือการใช้ Plugin ซึ่งจะจัดคิวคำขอที่ล้มเหลวโดยอัตโนมัติ แล้วลองอีกครั้งเมื่อเหตุการณ์ sync ในอนาคตเริ่มทำงาน

import {BackgroundSyncPlugin} from 'workbox-background-sync';
import {registerRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';

const bgSyncPlugin = new BackgroundSyncPlugin('myQueueName', {
  maxRetentionTime: 24 * 60, // Retry for max of 24 Hours (specified in minutes)
});

registerRoute(
  /\/api\/.*\/*.json/,
  new NetworkOnly({
    plugins: [bgSyncPlugin],
  }),
  'POST'
);

BackgroundSyncPlugin จะเชื่อมต่อกับ fetchDidFail โค้ดเรียกกลับและ fetchDidFail จะมีการเรียกใช้ก็ต่อเมื่อมีข้อยกเว้น ซึ่งน่าจะเป็นเพราะเครือข่ายล้มเหลว ซึ่งหมายความว่าระบบจะไม่ส่งคำขอซ้ำหากได้รับการตอบกลับซึ่งมีสถานะข้อผิดพลาด 4xx หรือ 5xx ที่ได้รับ หากต้องการลองคำขอทั้งหมดที่ส่งผลให้เกิด เช่น สถานะ 5xx อีกครั้ง คุณสามารถทำได้โดยเพิ่มปลั๊กอิน fetchDidSucceed ลงในกลยุทธ์ ดังนี้

const statusPlugin = {
  fetchDidSucceed: ({response}) => {
    if (response.status >= 500) {
      // Throwing anything here will trigger fetchDidFail.
      throw new Error('Server error.');
    }
    // If it's not 5xx, use the response as-is.
    return response;
  },
};

// Add statusPlugin to the plugins array in your strategy.

การใช้งานขั้นสูง

Workbox Background Sync ยังมีคลาส Queue ซึ่งคุณยืนยันและเพิ่มคำขอที่ล้มเหลวได้ ระบบจะจัดเก็บคำขอที่ล้มเหลวไว้ใน IndexedDB และจะลองใหม่เมื่อเบราว์เซอร์คิดว่าการเชื่อมต่อกลับมาใช้งานได้ (เช่น เมื่อได้รับเหตุการณ์การซิงค์)

การสร้างคิว

หากต้องการสร้างคิวการซิงค์เบื้องหลังของ Workbox คุณต้องสร้างคิวโดยใช้ชื่อคิว (ซึ่งต้องไม่ซ้ำกันสำหรับต้นทางของคุณ) โดยทำดังนี้

import {Queue} from 'workbox-background-sync';

const queue = new Queue('myQueueName');

ชื่อคิวใช้เป็นส่วนหนึ่งของชื่อแท็กที่ได้รับ register() โดยส่วนกลาง SyncManager และยังใช้ชื่อเป็น Object Store สำหรับฐานข้อมูล IndexedDB

การเพิ่มคำขอลงในคิว

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

import {Queue} from 'workbox-background-sync';

const queue = new Queue('myQueueName');

self.addEventListener('fetch', event => {
  // Add in your own criteria here to return early if this
  // isn't a request that should use background sync.
  if (event.request.method !== 'POST') {
    return;
  }

  const bgSyncLogic = async () => {
    try {
      const response = await fetch(event.request.clone());
      return response;
    } catch (error) {
      await queue.pushRequest({request: event.request});
      return error;
    }
  };

  event.respondWith(bgSyncLogic());
});

เมื่อเพิ่มลงในคิวแล้ว ระบบจะพยายามส่งคำขออีกครั้งโดยอัตโนมัติเมื่อโปรแกรมทำงานของบริการได้รับเหตุการณ์ sync (ซึ่งจะเกิดขึ้นเมื่อเบราว์เซอร์คิดว่าการเชื่อมต่อกลับมาเป็นปกติ) เบราว์เซอร์ที่ไม่รองรับ BackgroundSync API จะลองคิวใหม่ทุกครั้งที่โปรแกรมทำงานของบริการเริ่มต้น การตั้งค่านี้กำหนดให้หน้าที่ควบคุม Service Worker ทำงาน ดังนั้นจึงไม่ค่อยมีประสิทธิภาพมากนัก

การทดสอบการซิงค์ในเบื้องหลังของ Workbox

ที่น่าเศร้าที่การทดสอบ BackgroundSync นั้นค่อนข้างยุ่งยากและยากด้วยเหตุผลหลายประการ

วิธีที่ดีที่สุดในการทดสอบการติดตั้งใช้งานคือทำสิ่งต่อไปนี้

  1. โหลดหน้าเว็บและลงทะเบียน Service Worker
  2. ปิดเครือข่ายของคอมพิวเตอร์หรือปิดเว็บเซิร์ฟเวอร์
    • ห้ามใช้ Chrome DEVTOOLS แบบออฟไลน์ ช่องทำเครื่องหมายออฟไลน์ในเครื่องมือสำหรับนักพัฒนาเว็บจะส่งผลต่อคำขอจากหน้าเว็บเท่านั้น คำขอของ Service Worker จะต้องดำเนินการต่อไป
  3. สร้างคำขอเครือข่ายที่ควรอยู่ในคิวด้วย Workbox Background Sync
    • คุณตรวจสอบคำขอที่เข้าคิวได้โดยดูที่ Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests
  4. แล้วเปิดเครือข่ายหรือเว็บเซิร์ฟเวอร์ของคุณ
  5. บังคับใช้เหตุการณ์ sync ก่อนกำหนดโดยไปที่ Chrome DevTools > Application > Service Workers ป้อนชื่อแท็กของ workbox-background-sync:<your queue name> โดยที่ <your queue name> ควรเป็น ชื่อของคิวที่คุณตั้งไว้ แล้วคลิกปุ่ม "ซิงค์"

    ตัวอย่างปุ่มซิงค์ในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome

  6. คุณควรจะเห็นคำขอเครือข่ายที่ได้รับการดำเนินการสำหรับคำขอที่ล้มเหลว และข้อมูล IndexedDB ควรว่างเปล่าเนื่องจากคำขอได้รับการเล่นซ้ำสำเร็จแล้ว

ประเภท

BackgroundSyncPlugin

คลาสที่ใช้การเรียกกลับสำหรับวงจร fetchDidFail ซึ่งช่วยให้คุณเพิ่มคำขอที่ล้มเหลวไปยังคิวการซิงค์ในเบื้องหลังได้ง่ายขึ้น

พร็อพเพอร์ตี้

  • เครื่องมือสร้าง

    void

    ฟังก์ชัน constructor มีลักษณะดังนี้

    (name: string,options?: QueueOptions)=> {...}

    • ชื่อ

      string

      ดูรายละเอียดพารามิเตอร์ในเอกสารประกอบ workbox-background-sync.Queue

    • ตัวเลือก

      QueueOptions ไม่บังคับ

Queue

คลาสสำหรับจัดการการจัดเก็บคำขอที่ล้มเหลวใน IndexedDB และลองอีกครั้งในภายหลัง ทุกส่วนของกระบวนการจัดเก็บและเล่นซ้ำจะสังเกตได้ด้วยการเรียกกลับ

พร็อพเพอร์ตี้

  • เครื่องมือสร้าง

    void

    สร้างอินสแตนซ์ของคิวด้วยตัวเลือกที่ระบุ

    ฟังก์ชัน constructor มีลักษณะดังนี้

    (name: string,options?: QueueOptions)=> {...}

    • ชื่อ

      string

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

    • ตัวเลือก

      QueueOptions ไม่บังคับ

  • ชื่อ

    string

  • getAll

    void

    แสดงรายการทั้งหมดที่ยังไม่หมดอายุ (ต่อ maxRetentionTime) ระบบจะนำรายการที่หมดอายุออกจากคิว

    ฟังก์ชัน getAll มีลักษณะดังนี้

    ()=> {...}

    • returns

      Promise<QueueEntry[]>

  • popRequest

    void

    นำคำขอสุดท้ายในคิวออกและแสดงผล (พร้อมการประทับเวลาและข้อมูลเมตา) ออบเจ็กต์ที่แสดงผลจะอยู่ในรูปแบบ {request, timestamp, metadata}

    ฟังก์ชัน popRequest มีลักษณะดังนี้

    ()=> {...}

    • returns

      Promise<QueueEntry>

  • pushRequest

    void

    จัดเก็บคำขอที่ส่งผ่านใน IndexedDB (พร้อมด้วยการประทับเวลาและข้อมูลเมตา) ที่ส่วนท้ายของคิว

    ฟังก์ชัน pushRequest มีลักษณะดังนี้

    (entry: QueueEntry)=> {...}

    • รายการ

      QueueEntry

    • returns

      Promise<void>

  • registerSync

    void

    ลงทะเบียนเหตุการณ์การซิงค์ซึ่งมีแท็กเฉพาะสำหรับอินสแตนซ์นี้

    ฟังก์ชัน registerSync มีลักษณะดังนี้

    ()=> {...}

    • returns

      Promise<void>

  • replayRequests

    void

    วนซ้ำคำขอแต่ละรายการในคิวและพยายามดึงข้อมูลอีกครั้ง หากคำขอใดดึงข้อมูลอีกครั้งไม่สำเร็จ ระบบจะกลับไปที่ตำแหน่งเดิมในคิว (ซึ่งจะลงทะเบียนอีกครั้งสำหรับกิจกรรมการซิงค์ถัดไป)

    ฟังก์ชัน replayRequests มีลักษณะดังนี้

    ()=> {...}

    • returns

      Promise<void>

  • shiftRequest

    void

    นำออกและแสดงผลคำขอแรกในคิว (พร้อมกับการประทับเวลาและข้อมูลเมตา) ออบเจ็กต์ที่แสดงผลจะอยู่ในรูปแบบ {request, timestamp, metadata}

    ฟังก์ชัน shiftRequest มีลักษณะดังนี้

    ()=> {...}

    • returns

      Promise<QueueEntry>

  • ขนาด

    void

    แสดงผลจำนวนรายการที่แสดงในคิว โปรดทราบว่ารายการที่หมดอายุ (ต่อ maxRetentionTime) จะรวมอยู่ในจำนวนนี้ด้วย

    ฟังก์ชัน size มีลักษณะดังนี้

    ()=> {...}

    • returns

      คำมั่นสัญญา<number>

  • unshiftRequest

    void

    จัดเก็บคำขอที่ส่งผ่านใน IndexedDB (พร้อมการประทับเวลาและข้อมูลเมตา) ที่จุดเริ่มต้นของคิว

    ฟังก์ชัน unshiftRequest มีลักษณะดังนี้

    (entry: QueueEntry)=> {...}

    • รายการ

      QueueEntry

    • returns

      Promise<void>

QueueOptions

พร็อพเพอร์ตี้

  • forceSyncFallback

    บูลีน ไม่บังคับ

  • maxRetentionTime

    ตัวเลข ไม่บังคับ

  • onSync

    OnSyncCallback ไม่บังคับ

QueueStore

คลาสสำหรับจัดการการจัดเก็บคำขอจากคิวใน IndexedDB จัดทำดัชนีตามชื่อคิวของคิวเพื่อให้เข้าถึงได้ง่ายขึ้น

นักพัฒนาซอฟต์แวร์ส่วนใหญ่ไม่จำเป็นต้องเข้าถึงชั้นเรียนนี้โดยตรง เพราะมีการเปิดเผยไว้สำหรับ Use Case ขั้นสูง

พร็อพเพอร์ตี้

  • เครื่องมือสร้าง

    void

    เชื่อมโยงอินสแตนซ์นี้กับอินสแตนซ์คิวเพื่อให้ระบุรายการที่เพิ่มได้โดยใช้ชื่อคิว

    ฟังก์ชัน constructor มีลักษณะดังนี้

    (queueName: string)=> {...}

    • queueName

      string

  • deleteEntry

    void

    ลบรายการของรหัสที่ระบุ

    คำเตือน: เมธอดนี้ไม่ได้รับประกันว่ารายการที่ถูกลบจะเป็นของคิวนี้ (กล่าวคือ ตรงกับ queueName) แต่ข้อจำกัดนี้เป็นสิ่งที่ยอมรับได้เพราะคลาสนี้จะไม่เผยแพร่ต่อสาธารณะ การตรวจสอบเพิ่มเติมจะทำให้วิธีนี้ช้ากว่าที่ควรจะเป็น

    ฟังก์ชัน deleteEntry มีลักษณะดังนี้

    (id: number)=> {...}

    • id

      ตัวเลข

    • returns

      Promise<void>

  • getAll

    void

    แสดงรายการทั้งหมดใน Store ที่ตรงกับ queueName

    ฟังก์ชัน getAll มีลักษณะดังนี้

    ()=> {...}

    • returns

      Promise<QueueStoreEntry[]>

  • popEntry

    void

    นำรายการสุดท้ายในคิวที่ตรงกับ queueName ออกและแสดงผล

    ฟังก์ชัน popEntry มีลักษณะดังนี้

    ()=> {...}

    • returns

      Promise<QueueStoreEntry>

  • pushEntry

    void

    เพิ่มรายการต่อท้ายในคิว

    ฟังก์ชัน pushEntry มีลักษณะดังนี้

    (entry: UnidentifiedQueueStoreEntry)=> {...}

    • รายการ

      UnidentifiedQueueStoreEntry

    • returns

      Promise<void>

  • shiftEntry

    void

    นำรายการแรกในคิวที่ตรงกับ queueName ออกและแสดงผล

    ฟังก์ชัน shiftEntry มีลักษณะดังนี้

    ()=> {...}

    • returns

      Promise<QueueStoreEntry>

  • ขนาด

    void

    แสดงผลจำนวนรายการใน Store ที่ตรงกับ queueName

    ฟังก์ชัน size มีลักษณะดังนี้

    ()=> {...}

    • returns

      คำมั่นสัญญา<number>

  • unshiftEntry

    void

    เพิ่มรายการไว้หน้ารายการก่อนในคิว

    ฟังก์ชัน unshiftEntry มีลักษณะดังนี้

    (entry: UnidentifiedQueueStoreEntry)=> {...}

    • รายการ

      UnidentifiedQueueStoreEntry

    • returns

      Promise<void>

StorableRequest

คลาสที่ง่ายขึ้นในการเรียงอันดับคำขอและแยกอนุกรมวิธาน เพื่อให้จัดเก็บคำขอเหล่านั้นใน IndexedDB

นักพัฒนาซอฟต์แวร์ส่วนใหญ่ไม่จำเป็นต้องเข้าถึงชั้นเรียนนี้โดยตรง เพราะมีการเปิดเผยไว้สำหรับ Use Case ขั้นสูง

พร็อพเพอร์ตี้

  • เครื่องมือสร้าง

    void

    ยอมรับออบเจ็กต์ของข้อมูลคำขอที่ใช้สร้าง Request ได้ แต่สามารถจัดเก็บไว้ใน IndexedDB ได้ด้วย

    ฟังก์ชัน constructor มีลักษณะดังนี้

    (requestData: RequestData)=> {...}

    • requestData

      RequestData

      ออบเจ็กต์ของข้อมูลคำขอที่มี url รวมถึงพร็อพเพอร์ตี้ที่เกี่ยวข้องของ [requestInit]https://fetch.spec.whatwg.org/#requestinit

  • การโคลน

    void

    สร้างและแสดงผลการโคลนของอินสแตนซ์ในระดับลึก

    ฟังก์ชัน clone มีลักษณะดังนี้

    ()=> {...}

  • toObject

    void

    แสดงผลการโคลนของออบเจ็กต์ _requestData ของอินสแตนซ์

    ฟังก์ชัน toObject มีลักษณะดังนี้

    ()=> {...}

    • returns

      RequestData

  • toRequest

    void

    แปลงอินสแตนซ์นี้เป็นคำขอ

    ฟังก์ชัน toRequest มีลักษณะดังนี้

    ()=> {...}

    • returns

      ส่งคำขอ

  • fromRequest

    void

    แปลงออบเจ็กต์คำขอเป็นออบเจ็กต์ธรรมดาที่โคลนหรือสตริง JSON ได้

    ฟังก์ชัน fromRequest มีลักษณะดังนี้

    (request: Request)=> {...}

    • ส่งคำขอ

      ส่งคำขอ