如何在 Manifest v3 中使用 localStorage 或替代方案

xow*_*108 11 google-chrome google-chrome-extension chrome-extension-manifest-v3

我正在尝试将 Chrome 扩展程序切换为使用 Manifest v3。

除了我正在使用的地方之外,我已经得到了一切localStorage

if (localStorage.getItem(lastchecked[0]) < Date.now() - 2500000000) {
    localStorage.setItem(lastchecked[0], Date.now());
} else {
    const remover = Date.now() - 2500000000;
    Object.entries(localStorage).forEach(([k, v]) => {
        if (v < remover) {
            delete localStorage[k];
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

这是我收到的错误:

ReferenceError: localStorage is not defined
Run Code Online (Sandbox Code Playgroud)

据我所知,这是因为我将扩展从使用背景切换script为使用service worker,这似乎无法访问localStorage.

localStorage除了它不可用之外,还有什么简单的方法可以将其切换为使用其他东西吗?

wOx*_*xOm 16

localStorage根据规范,在 Service Worker 中不可用。原因是,由于它提供同步访问,因此必须在启动 JS 环境之前完整读取它,这可能需要一些时间,与环境本身的启动时间(~50ms)相当,如果存储包含几兆字节(最大为 5MB)。

Service Worker 中仅提供异步存储 API。
扩展可以使用这些:

  • 铬存储

    • 好:少量简单数据
    • 好:直接在内容脚本中可用
    • meh:仅兼容 JSON 的类型(字符串、数字、布尔值、null、由这些类型递归组成的对象/数组),因此尝试存储复杂的内容(例如Set或 )Map最终会成为一个空对象{},您必须将它们序列化,例如[...mySet]写作时,new Set(result.foo)阅读时。
    • 不好:对于大数据/嵌套数据来说非常慢
  • 索引数据库

    • 好:对于任何数量/复杂性的数据都非常快
    • 好:更多数据类型,如 ArrayBuffer、File、Blob、类型化数组、Set、Map,
      请参阅结构化克隆算法
    • 嗯:数据在内容脚本中不可用,因此您必须使用消息传递
    • 缺点:它的 API 过时且笨拙,但有几个库可以修复它

这些 API 是异步的,因此您必须重新编写代码。
从 Chrome 95 promisified 开始chrome.storage,我们可以使用 async/await 作为示例。
并且不要忘记添加"storage""permissions"manifest.json中。

const LS = chrome.storage.local;

async function pruneStorage() {
  const remover = Date.now() - 2500000000;
  const key = lastchecked[0];
  if ((await LS.get(key))[key] < remover) {
    await LS.set({[key]: Date.now()});
  } else {
    const toRemove = Object.entries(await LS.get())
      .map(([k, v]) => v < remover && k)
      .filter(Boolean);
    if (toRemove.length) {
      await LS.remove(toRemove);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

或者,模仿localStorage

const LS = {
  getAllItems: () => chrome.storage.local.get(),
  getItem: async key => (await chrome.storage.local.get(key))[key],
  setItem: (key, val) => chrome.storage.local.set({[key]: val}),
  removeItems: keys => chrome.storage.local.remove(keys),
};

async function pruneStorage() {
  const remover = Date.now() - 2500000000;
  const key = lastchecked[0];
  if (await LS.getItem(key) < remover) {
    await LS.setItem(key, Date.now());
  } else {
    const toRemove = Object.entries(await LS.getAllItems())
      .map(([k, v]) => v < remover && k)
      .filter(Boolean);
    if (toRemove.length) {
      await LS.removeItems(toRemove);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

async警告:如果您想异步发送响应,请不要创建 chrome.runtime.onMessage 侦听器,请使用异步 IIFE 或单独的函数,更多信息

  • 不,这是不可能的。将来,Chrome 将拥有 chrome.offscreen API,它会启动一个隐藏的 DOM 页面,该页面可以访问 localStorage,然后通过消息将其发送到后台脚本。同时,您必须在更新时打开一个“入门”页面,该页面将欢迎用户并转换存储空间。您需要设置一个“beforeunload”侦听器,以防止在工作完成之前意外关闭页面。 (3认同)