天天看點

浏覽器支援Periodic Background Sync?周期性同步事件!

作者:前端進階

大家好,很高興又見面了,我是"前端‬進階‬",由我帶着大家一起關注前端前沿、深入前端底層技術,大家一起進步,也歡迎大家關注、點贊、收藏、轉發!

浏覽器支援Periodic Background Sync?周期性同步事件!

什麼是Periodic Background Sync?

Periodic Background Synchronization 提供了一種方法來注冊要在具有網絡連接配接的service worker中定期運作的任務,這些任務稱為定期背景同步請求。

Periodic Background Sync API 允許 Web 應用程式以周期性的時間間隔通知 service worker 進行内容更新。 比如在裝置連接配接到 Wi-Fi 時擷取最新内容,或允許對應用程式進行背景更新。

什麼是Periodic Background Sync?

調用API時需要設定最小時間間隔, 但是使用者代理也可能會考慮其他影響 service worker 接收事件的因素。 例如,之前的網站參與或與已知網絡的連接配接。

PeriodicSyncManager 接口可通過 ServiceWorkerRegistration.periodicSync 獲得。 一個唯一的标簽辨別符被設定為“name”同步事件,然後可以在 ServiceWorker 腳本中偵聽該事件。 一旦收到事件,您就可以運作任何可用的功能,例如更新緩存或擷取新資源。

由于此 API 依賴于service worker,是以此 API 提供的功能僅在安全上下文中可用。

if (window.isSecureContext) {
  // 上下文安全
  navigator.serviceWorker.register("/offline-worker.js").then(() => {
    // …
  });
}           

使用定期背景同步 API

Service Worker加載完成後,可以使用Permissions API查詢periodic-background-sync狀态。可以在window或service worker上下文中執行此操作。

// permissions API查詢狀态
const status = await navigator.permissions.query({
  name: 'periodic-background-sync',
});
if (status.state === 'granted') {
  // Periodic background sync可用
} else {
  // Periodic background sync不可用
}           

注冊定期同步需要标記最小同步間隔 (minInterval), 該标簽辨別已注冊的定期同步,同時允許注冊多個任務。 在下面的示例中,标簽名稱是“content-sync”,minInterval 是一天。

navigator.serviceWorker.ready.then(async registration => {
  try {
   //注冊标簽名稱是“content-sync”的任務
	await registration.periodicSync.register('get-cats', { minInterval: 24 * 60 * 60 * 1000 });
    console.log(Periodic background sync registered.');
  } catch (err) {
    console.error(err.name, err.message);
  }
});           

調用 periodicSync.getTags() 可以檢索注冊标簽數組。下面的示例使用标記名稱來确認緩存更新處于活動狀态以避免重複更新。

const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
  const tags = await registration.periodicSync.getTags();
  // 僅在未設定同步時更新内容。
  if (!tags.includes('content-sync')) {
    updateContentOnPageLoad();
  }
} else {
  //如果不支援定期背景同步,請始終更新
  updateContentOnPageLoad();
}           

要響應周期性背景同步事件,請将周期性同步事件處理程式添加到service worker。 傳遞給它的事件對象将包含一個與注冊期間使用值相比對的标簽參數。 例如,如果使用名稱為“content-sync”注冊了定期背景同步,則 event.tag 将為“content-sync”

self.addEventListener('periodicsync', (event) => {
  if (event.tag === 'content-sync') {
    // event.tag與注冊時候相同
    event.waitUntil(syncContent());
  }
});           

Chrome如何調試Periodic Background Sync

記錄本地活動

DevTools 的定期背景同步部分圍繞定期背景同步生命周期中的關鍵事件進行組織。包括生命周期完整流程:注冊同步、執行背景同步和登出。 要擷取有關事件的資訊,請單擊record按鈕。

浏覽器支援Periodic Background Sync?周期性同步事件!

DevTools 中的記錄按鈕

記錄時,條目将出現在與事件對應的 DevTools 中,并為每個條目記錄上下文和中繼資料。

浏覽器支援Periodic Background Sync?周期性同步事件!

記錄周期性背景同步資料的示例

啟用一次記錄後,它将保持啟用狀态長達三天,允許 DevTools 捕獲有關可能發生的背景同步的本地調試資訊。

模拟事件

雖然記錄背景活動可能會有所幫助,但有時希望立即測試 periodicsync 處理程式,而不是等待事件讓其以正常節奏觸發。

您可以通過 Chrome DevTools 應用程式面闆中的 Service Workers 部分執行此操作。 Periodic Sync 字段允許您為要使用的事件提供标簽,并根據需要多次觸發它。

浏覽器支援Periodic Background Sync?周期性同步事件!
手動觸發 periodicsync 事件需要 Chrome 81 或更高版本。

Chrome 81以後的版本中,在DevTools 應用程式面闆中可以看到定期背景同步部分。

浏覽器支援Periodic Background Sync?周期性同步事件!

Periodic Background Sync浏覽器支援

如下圖所示,浏覽器的整體的支援力度為75.26%。Chrome從49版本,Edge從79版本,Opera從42版本已經支援了Periodic Background Synchronization。FireFox、Safari在最新釋出的版本中暫時還未支援該特性。

浏覽器支援Periodic Background Sync?周期性同步事件!

Periodic Background Sync完整示例

HTML示例代碼

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
      rel="icon"
      href=""
    />
    <link rel="manifest" href="./manifest.json" />
    <title>How to periodically synchronize data in the background</title>
    <link rel="stylesheet" href="/style.css" />
    <script src="/script.js" defer></script>
  </head>
  <body>
    <h1>How to periodically synchronize data in the background</h1>
    <p class="available">Periodic background sync can be used. Install the app first.</p>
    <p class="not-available">Periodic background sync cannot be used.</p>
    <h2>Last updated</h2>
    <p class="last-updated">Never</p>
    <h2>Registered tags</h2>
    <ul>
      <li>None yet.</li>
    </ul>
  </body>
</html>           

JS完整代碼

const available = document.querySelector('.available');
const notAvailable = document.querySelector('.not-available');
const ul = document.querySelector('ul');
const lastUpdated = document.querySelector('.last-updated');

const updateContent = async () => {
  const data = await fetch(
    'https://worldtimeapi.org/api/timezone/Europe/London.json'
  ).then((response) => response.json());
  return new Date(data.unixtime * 1000);
};

const registerPeriodicBackgroundSync = async (registration) => {
  const status = await navigator.permissions.query({
    name: 'periodic-background-sync',
  });
  if (status.state === 'granted' && 'periodicSync' in registration) {
    try {
      // Register the periodic background sync.
      await registration.periodicSync.register('content-sync', {
        // An interval of one day.
        minInterval: 24 * 60 * 60 * 1000,
      });
      available.hidden = false;
      notAvailable.hidden = true;

      // List registered periodic background sync tags.
      const tags = await registration.periodicSync.getTags();
      if (tags.length) {
        ul.innerHTML = '';
      }
      tags.forEach((tag) => {
        const li = document.createElement('li');
        li.textContent = tag;
        ul.append(li);
      });

      // Update the user interface with the last periodic background sync data.
      const backgroundSyncCache = await caches.open('periodic-background-sync');
      if (backgroundSyncCache) {
        const backgroundSyncResponse =
          backgroundSyncCache.match('/last-updated');
        if (backgroundSyncResponse) {
          lastUpdated.textContent = `${await fetch('/last-updated').then(
            (response) => response.text()
          )} (periodic background-sync)`;
        }
      }

      // Listen for incoming periodic background sync messages.
      navigator.serviceWorker.addEventListener('message', async (event) => {
        if (event.data.tag === 'content-sync') {
          lastUpdated.textContent = `${await updateContent()} (periodic background sync)`;
        }
      });
    } catch (err) {
      console.error(err.name, err.message);
      available.hidden = true;
      notAvailable.hidden = false;
      lastUpdated.textContent = 'Never';
    }
  } else {
    available.hidden = true;
    notAvailable.hidden = false;
    lastUpdated.textContent = `${await updateContent()} (manual)`;
  }
};

if ('serviceWorker' in navigator) {
  window.addEventListener('load', async () => {
    const registration = await navigator.serviceWorker.register('./sw.js');
    console.log('Service worker registered for scope', registration.scope);

    await registerPeriodicBackgroundSync(registration);
  });
}           

CSS代碼

html {
  box-sizing: border-box;
  font-family: system-ui, sans-serif;
  color-scheme: dark light;
}
*,
*:before,
*:after {
  box-sizing: inherit;
}

body {
  margin: 1rem;
}           

完整示例代碼可以檢視文末參考資料。

本文總結

本文主要和大家介紹下浏覽器支援的Periodic Background Sync,即周期性同步事件,同時給出了簡單的用法示例。因為筆者也沒有在生産項目中使用、部署過Periodic Background Sync,是以隻是做了一個簡短的介紹,但是文末的參考資料提供了大量優秀文檔以供學習,如果有興趣可以自行閱讀。如果大家有什麼疑問歡迎在評論區留言。

參考資料

https://web.dev/patterns/advanced-apps/periodic-background-sync/

https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts

https://web.dev/patterns/advanced-apps/periodic-background-sync/demo.html

https://developer.chrome.com/articles/periodic-background-sync/

繼續閱讀