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

How to use localStorage or an alternative in 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];
        }
    });
}

这是我遇到的错误:

ReferenceError: localStorage is not defined

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

除了 localStorage 之外,是否有任何简单的方法可以将其切换为使用其他东西,因为它不可用?

根据规范,

localStorage 在 service worker 中不可用。原因是因为它提供同步访问,所以在启动 JS 环境之前必须完整读取它,这可能需要一些时间,这与环境本身的启动时间(~50ms)相当,以防存储包含几兆字节(最大为 5MB)。

Service Worker 中只有异步存储 API 可用。
扩展可以使用这些:

  • chrome.storage

    • 好:数据量小
    • 好:直接在内容脚本中可用
    • meh:只有 JSON 兼容的类型(字符串、数字、布尔值、null,object/array 由这些类型递归组成),因此试图存储复杂的东西,如 SetMap 将以空对象 {} 结束,您必须 序列化 它们,例如写入时[...mySet],读取时new Set(result.foo)
    • 不好:big/nested 数据非常慢
  • IndexedDB

    • 好:对于任何 amount/complexity 数据都非常快
    • 好:更多数据类型,如 ArrayBuffer、File、Blob、类型化数组、Set、Map,
      查看 structured clone algorithm
    • meh:数据在内容脚本中不可用,因此您必须使用 messaging
    • 不好:它的 API 已经过时且笨拙,但是有几个库可以修复它

这些 API 是异步的,因此您将不得不重新编写代码。
由于 Chrome 95 promified chrome.storage,我们可以使用 async/await 作为您的示例。
并且不要忘记在 manifest.json.

中添加 "storage""permissions"
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);
    }
  }
}

或者,模仿 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);
    }
  }
}

警告:如果您想异步发送响应,请不要让您的 chrome.runtime.onMessage 侦听器 async,请改用异步 IIFE 或单独的函数,