Service Worker
擴(kuò)展程序 Service Worker 是擴(kuò)展程序的核心事件處理腳本。這使得它們與 Web Service Worker 明顯不同
Extension Service Worker 與 Web Service Worker 有一些共同點(diǎn)。擴(kuò)展 Service Worker 在需要時(shí)加載,并在其進(jìn)入休眠狀態(tài)時(shí)取消加載。只要擴(kuò)展程序 Service Worker 在加載后還會主動接收事件,它就會運(yùn)行,不過它可以關(guān)閉。與對應(yīng)的 Web 應(yīng)用一樣,擴(kuò)展 Service Worker 無法訪問 DOM,不過可以根據(jù)需要將其用于 offscreen。
擴(kuò)展程序 Service Worker 不只是網(wǎng)絡(luò)代理(因?yàn)榻?jīng)常會提到 Web Service Worker)。除了標(biāo)準(zhǔn) Service Worker 事件之外,它們還會響應(yīng)擴(kuò)展程序事件,例如導(dǎo)航到新頁面、點(diǎn)擊通知或關(guān)閉標(biāo)簽頁。它們的注冊和更新方式也與 Web Service Worker 不同。
一、注冊 Service Worker
要注冊擴(kuò)展 Service Worker,先在 manifest.json 文件的 "background" 字段中指定它。使用 "service_worker" 字段,該字段會指定單個(gè) JavaScript 文件。
{
"name": "Awesome Test Extension",
"background": {
"service_worker": "service-worker.js"
},
}
二、導(dǎo)入腳本
將腳本導(dǎo)入 Service Worker 的方法有兩種:import 語句和 importScripts() 方法。
如需使用 import 語句,請將 "type" 字段添加到 manifest.json 文件中并指定 "module"。
"background": {
"service_worker": "service-worker.js",
"type": "module"
}
然后,像往常一樣使用 import。請注意,不支持導(dǎo)入斷言。
import { tldLocales } from './locales.js';
像在 Web Service Worker 中一樣使用 importScripts()。
importScripts('locales.js');
1.1. 導(dǎo)入多個(gè) Service Worker 模塊
我們的 Service Worker 實(shí)現(xiàn)了兩項(xiàng)功能。為了提高可維護(hù)性,我們將在單獨(dú)的模塊中實(shí)現(xiàn)每項(xiàng)功能。首先,我們需要在 manifest.json 文件中將 Service Worker 聲明為一個(gè) ES module,這樣我們就可以將模塊導(dǎo)入到 Service Worker 中:
-
manifest.json:
{
"background": {
"service_worker": "service-worker.js",
"type": "module"
},
}
- 創(chuàng)建
service-worker.js文件并導(dǎo)入兩個(gè)模塊:
import './sw-omnibox.js';
import './sw-tips.js';
- 創(chuàng)建這些文件并為每個(gè)文件添加控制臺日志。
- sw-omnibox.js:
console.log("sw-omnibox.js")
- sw-tips.js:
console.log("sw-tips.js")
三、更新
要更新 Service Worker,向 Chrome 應(yīng)用商店發(fā)布新版本的擴(kuò)展程序。無法通過從服務(wù)器加載擴(kuò)展程序來解決此問題。出于安全原因,Manifest V3 不支持遠(yuǎn)程托管的代碼。
Service Worker 必須是擴(kuò)展程序軟件包的一部分。
四、Service Worker 事件
擴(kuò)展程序 Service Worker 同時(shí)支持標(biāo)準(zhǔn) Service Worker 事件和擴(kuò)展程序 API 中的許多事件。
1. 聲明擴(kuò)展程序事件
Service Worker 中的事件處理腳本需要在全局范圍內(nèi)聲明,這意味著它們應(yīng)該位于腳本的頂層,而不應(yīng)嵌套在函數(shù)內(nèi)。這樣可以確保它們在腳本初始執(zhí)行時(shí)同步注冊,從而使 Chrome 能夠在 Service Worker 啟動后立即將事件分派給它。
chrome.action.onClicked.addListener(handleActionClick);
chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
chrome.action.setBadgeText({ text: badgeText });
});
2. 常見事件
2.1. chrome.action
當(dāng)有用戶與擴(kuò)展程序的工具欄圖標(biāo)互動時(shí)觸發(fā),無論該操作是針對特定網(wǎng)頁(標(biāo)簽頁)還是整個(gè)擴(kuò)展程序。
2.2. chrome.management
提供與安裝、卸載、啟用和停用擴(kuò)展程序相關(guān)的事件。
2.3. chrome.notifications
提供與用戶與擴(kuò)展程序生成的系統(tǒng)通知互動相關(guān)的事件。
2.4. chrome.permissions
指示用戶何時(shí)授予或撤消擴(kuò)展程序權(quán)限。
2.5. chrome.runtime
提供與擴(kuò)展程序生命周期相關(guān)的事件、擴(kuò)展程序的其他部分發(fā)送的消息,以及可用擴(kuò)展程序或 Chrome 更新的通知。
2.6. chrome.storage.onChanged
每當(dāng)任何 StorageArea 對象被清除或某個(gè)鍵的值被更改或設(shè)置時(shí)觸發(fā)。請注意,每個(gè) StorageArea 實(shí)例都有自己的 onChanged 事件。
2.7. chrome.webNavigation
提供有關(guān)飛行中導(dǎo)航請求狀態(tài)的信息。
3. 過濾 Filter
要將事件限制為特定用例,或消除不必要的事件調(diào)用,請使用支持事件過濾器的 API。例如,假設(shè)某個(gè)擴(kuò)展程序會監(jiān)聽 tabs.onUpdated 事件,以檢測用戶何時(shí)導(dǎo)航到特定網(wǎng)站。系統(tǒng)會在每個(gè)標(biāo)簽頁上的每次導(dǎo)航時(shí)調(diào)用此事件。請改為搭配使用 webNavigation.onCompleted 和過濾條件。
const filter = {
url: [
{
urlMatches: 'https://www.google.com/',
},
],
};
chrome.webNavigation.onCompleted.addListener(() => {
console.info("The user has loaded my favorite website!");
}, filter);
五、Service Worker 生命周期
1. 安裝
當(dāng)用戶從 Chrome 應(yīng)用商店安裝或更新 Service Worker,或者用戶使用 chrome://extensions 頁面加載或更新已解壓的擴(kuò)展程序時(shí),就會發(fā)生安裝。按以下順序發(fā)生三個(gè)事件。
1.1. ServiceWorkerRegistration.install
安裝期間觸發(fā)的第一個(gè)事件是 Web Service Worker 的 install 事件。
1.2. chrome.runtime.onInstalled
接下來是該擴(kuò)展程序的 onInstalled 事件,當(dāng)該擴(kuò)展程序(而不是 Service Worker)首次安裝時(shí)、該擴(kuò)展程序更新到新版本以及 Chrome 更新到新版本時(shí),都會觸發(fā)該事件。使用此事件來設(shè)置狀態(tài)或一次性初始化,例如上下文菜單。
chrome.runtime.onInstalled.addListener((details) => {
if(details.reason !== "install" && details.reason !== "update") return;
chrome.contextMenus.create({
"id": "sampleContextMenu",
"title": "Sample Context Menu",
"contexts": ["selection"]
});
});
1.3. ServiceWorkerRegistration.active
最后,系統(tǒng)將觸發(fā) Service Worker 的 activate 事件。請注意,與 Web Service Worker 不同,此事件會在安裝擴(kuò)展程序后立即觸發(fā),因?yàn)闆]有與擴(kuò)展程序中的頁面重新加載相媲美的功能。
2. 插件啟動
當(dāng) user profile 啟動時(shí),會觸發(fā) chrome.runtime.onStartup 事件,但不會調(diào)用任何 Service Worker 事件。
3. 閑置和關(guān)閉
通常,Chrome 會在滿足以下條件之一時(shí)終止 Service Worker:
- 無操作 30 秒后。收到事件或調(diào)用擴(kuò)展程序
API會重置此計(jì)時(shí)器。 - 單個(gè)請求(例如事件或 API 調(diào)用)的處理用時(shí)超過 5 分鐘。
- 當(dāng)
fetch()響應(yīng)的傳遞時(shí)間超過 30 秒時(shí)。
事件和對擴(kuò)展程序 API 的調(diào)用會重置這些計(jì)時(shí)器,如果 Service Worker 已休眠,傳入事件將使它們恢復(fù)。應(yīng)該將 Service Worker 設(shè)計(jì)為能夠靈活應(yīng)對意外終止。
4. 保存數(shù)據(jù)
如果 Service Worker 關(guān)閉,設(shè)置的任何全局變量都將丟失。將值保存到存儲空間,而不是使用全局變量。請注意,Web Storage API 不適用于擴(kuò)展程序 Service Worker。
4.1. chrome.storage API
一種擴(kuò)展程序 API,提供多種存儲類型;本地存儲、會話存儲、托管(網(wǎng)域)和同步存儲。此 API 用于存儲使用開發(fā)者定義的密鑰識別和檢索的 JSON 對象。當(dāng)用戶清除網(wǎng)頁緩存時(shí),此類存儲空間不會移除。
4.2. IndexedDB API
用于在客戶端存儲結(jié)構(gòu)化數(shù)據(jù)(包括文件和 blob)的低級別 API。此 API 提供了用于創(chuàng)建事務(wù)型數(shù)據(jù)存儲和檢索的原語。雖然此 API 通常對于簡單的使用場景而言過于復(fù)雜,但在此基礎(chǔ)上構(gòu)建了許多第三方存儲解決方案。
4.3. CacheStorage API
請求和響應(yīng)對象對的永久性存儲機(jī)制。此 API 專為 Web Service Worker 設(shè)計(jì),用于從端點(diǎn)檢索數(shù)據(jù)??赏ㄟ^多種方式使用此 API,具體取決于用戶是否查看最新數(shù)據(jù)及其重要性。有關(guān)詳情,請參閱離線指南。除非專門通過提取處理程序來代理網(wǎng)絡(luò)請求,否則應(yīng)使用 chrome.storage。