Skip to main content
一個擴充功能有四個儲存區域,而且它們不能互相替代。local 保存裝置上的資料,sync 在已登入的設定檔之間攜帶少量偏好,session 只要瀏覽器在執行就留在記憶體裡,managed 則是唯讀的政策資料。本頁給出每個區域的配額與可讀方,說明讓 storage.session 遠離 content script 的規則,以及區域寫滿或被限流時印出的主控台行。

保存狀態的三種方式,以及為什麼 storage 勝出

service worker 裡的變數。 Manifest V3 的背景 service worker 會在閒置時停止,並在下一個事件到來時重新啟動。你放在記憶體裡的一切都消失了,而且沒有任何錯誤來提醒你。 擴充功能頁面裡的 localStorage 或 IndexedDB。 兩者都以頁面來源為範圍。service worker 根本不能使用 localStorage,而 content script 看到的是宿主頁面的儲存,不是你的。 一個 chrome.storage 區域。 非同步,任何擁有 storage 權限的擴充功能情境都能讀取,也不受 worker 重新啟動影響。這是擴充功能狀態的預設答案。

四個儲存區域

下面的配額是 Chromium 的預設值。 sync 還會限流寫入:大約每分鐘 120 次、每小時 1,800 次。放在按鍵處理常式裡的寫入會很快撞到這個上限,所以請做去抖動,只寫一次。 依資料回答的問題來選擇:
  • 功能狀態、快取與持久設定放在 local
  • 使用者期望在第二台電腦上看到的少量偏好放在 sync
  • 不該活過瀏覽器的單次執行協調資料放在 session
  • 企業政策值從 managed 讀取,絕不與使用者可編輯的設定混在一起。
chrome.storage 不是唯一的選擇。IndexedDB 和來源私有檔案系統(OPFS)可以在擴充功能頁面和 worker 中存放大量或結構化資料,受瀏覽器的一般配額約束。在 content script 中,兩者都屬於宿主頁面的來源,因此請把這類資料放在擴充功能自己的情境裡。

Manifest 片段

storage 權限涵蓋全部四個區域。unlimitedStorage 提高 local 的上限,managed 需要一個 schema 檔案:
一個從儲存還原、而不是信任記憶體的設定模組:

從 content script 讀取 storage.session

storage.session 一開始對不受信任的情境是關閉的,而 content script 正是這種情境。從那裡讀取會擲出錯誤,而不是回傳一個空物件。請在 content script 發出請求之前,從 service worker 裡開放一次這個區域:
當值是敏感的時候,讓區域保持關閉。改為透過一則送往 service worker 的訊息來完成讀取,做法請見 訊息傳遞

各瀏覽器差異

Firefox 實作了全部四個區域。請把配額表裡的數字當作 Chromium 的,並在發布前對著 Firefox 建置核對你的功能所依賴的那個上限。 如果你的原始碼呼叫 browser.storage,同時也要建置 Chromium 目標,請傳入 --polyfill。請見 跨瀏覽器相容

你會看到的主控台錯誤

把你看到的那一行複製去搜尋。每一行對應一個原因。 QUOTA_BYTES_PER_ITEM quota exceeded 一個 sync 鍵之下的單一值大於 8 KB。把這個值拆到多個鍵,或者把該鍵移到 local QUOTA_BYTES quota exceeded 區域滿了:sync 是所有鍵合計 100 KB,local 是裝置上限。存少一點,或者為 local 這種情況加上 unlimitedStorage MAX_WRITE_OPERATIONS_PER_MINUTE quota exceeded 一分鐘內的 sync 寫入過多,通常是每次按鍵或每次捲動都寫一次。給處理常式做去抖動,只寫一次穩定後的值。 Access to storage is not allowed from this context. content script 在區域仍然僅限受信任情境時讀取了 storage.session。請從 service worker 呼叫 setAccessLevel,或者把讀取放到一則訊息之後。 回呼風格的呼叫透過 chrome.runtime.lastError 回報這些錯誤,而在你去讀它之前它是靜默的。Promise 形式會 reject,因此在 try 區塊裡 await,你會看到同樣的文字作為被捕捉的錯誤。

Extension.js 的做法

Extension.js 不包裝也不取代儲存 API。它只編譯呼叫這些 API 的程式碼,因此上面的平台規則就是全部約定。有兩個建置行為值得知道:
  • storage.managed_schema 路徑會被驗證,schema 檔案會被產出到輸出目錄。該路徑必須解析到擴充功能目錄內的檔案。Extension.js 會在瀏覽器啟動前把指向目錄之外的路徑標記為載入阻斷,因為 Chrome 會因為缺少 managed schema 而拒絕整個擴充功能。請見 JSON
  • --polyfill 會把 browser.* 橋接到 Chromium 目標上,因此同一份原始碼可以為兩個家族呼叫 browser.storage
因為背景 service worker 會重新啟動,請寫下重要的狀態並按需讀回。把記憶體裡的副本當作最佳化,永遠不要當作事實來源。背景腳本 說明了這個重新啟動模型。 在第一個版本之前就為你儲存的資料形狀定好版本,並為重新命名的鍵保留移轉路徑。存下來的物件會比寫下它的程式碼活得更久。

參見