Skip to content

一、前言 ​

chrome 插件之所以如此受欢迎,是因为它为开发者提供了完备的 API,本篇文章就来介绍一下 chrome 插件的存储系统,也就是说 chrome 为我们提供了类似我们在 web 环境下使用localStorage和sessionStorage的 API。

这个 API 位于 chrome 环境下的chrome.storage,以下我们将 chrome 插件提供的存储能力统称为 StorageAPI。

二、概览 ​

1.是什么? ​

StorageAPI 为我们提供了在 chrome 插件环境下持久化存储数据和状态的能力,就像 web 端的 API IndexedDB, 和  Storage一样,但是相比他们,StorageAPI 更加符合 chrome 插件的需要,并且具备以下特性:

  • 所有的 chrome 插件环境中都可以访问 StroageAPI,因此可以很方便的管理全局的状态。
  • 使用 webStorage 时,我们需要将想要存储的对象序列化,否则无法实现我们希望的存储,但是 StorageAPI 可以直接存储一个对象,便于开发者维护和管理。
  • StorageAPI 是异步的,采用批量读写的操作。
  • 即使用户清除浏览器缓存或历史,StorageAPI 依然为我们持久化存储数据状态。

2.为什么需要? ​

qs:为什么不直接使用 webStorage?

众所周知,我们在 chrome 插件中也可以使用 webStorage,例如在 content.js 、pupop.html、chrome.tabs.create({url:"path"}) 创建的新 tab 等中都可以使用 webStorage。那为什么还需要 StorageAPI 呢?主要是由于以下原因:

  • background.js 脚本无法访问 webStorage,因为它只是一个脚本运行环境,不承载任何 UI 界面。
  • content.js 和宿主站点是共享 webStorage 的,宿主环境的脚本也有可能修改 webStorage 的状态。
  • 当我们清除浏览器缓存后,webStorage 就一并消失了。

基于以上的原因,chrome 插件希望为自己提供一套统一的、干净的、更强大的全局存储状态的工具,才有了 StorageAPId 的出现。

3.有哪些类型? ​

StorageAPI 有四个不同的区域来实现不同特性的存储功能:

storage.local

这个区域属于本地存储,只有当插件被移除卸载后数据才会被清除,所以你关闭浏览器或者清除浏览器缓存都无法将所存储的状态清除。

它的存储大小限制在 10MB 以内,当然如果在manifest.json的permission配置中添加"unlimitedStorage"配置的话,它的存储限制会进一步被提高。

温馨提示:
在 chrome114 之前的版本,它的默认限制是 5MB。

storage.sync

image

在 chrome 设置中,我们可以选择开启同步模式,它的好处就是对于同一个用户而言,所有登录谷歌账号的终端设备都可以共享部分数据。换句话说,如果我拥有一个谷歌账号,我在不同主机上的浏览器可以共享一些数据。

而 sync 就支持这样的功能,通过storage.sync可以获取同一用户的不同终端的全量的数据和状态。当然如果没有开启同步模式的时候,它的表现就和storage.local是一样的。

当浏览器离线时,Chrome 将数据存储在本地,并在重新上线时恢复同步,它的存储限制大约为 100 KB。我们可以考虑使用它来保存跨同步浏览器的用户设置。

storage.local 和 storage.sync 不应该存储机密用户数据,因为它们没有加密。在处理敏感数据时,考虑使用会话存储区域在内存中保存值,直到浏览器关闭。

storage.session

如果说 storage.local 和 storage.sync 是存储在磁盘上的话,storage.session 在浏览器会话期间将数据保存在内存中。默认情况下,它不会暴露给内容脚本,但是可以通过设置 chrome.storage.session.setAccessLevel()来改变这种行为,存储限制大约是 10BM。考虑使用它来存储跨 service worker 运行的全局变量。

storage.manage

该存储区域是只读的,一般不会用到它,需要声明一个 schema.json 才可以使用该 API。

4.条件 ​

要真正的在 chorme 插件环境中使用,需要我们在 manifest.json 中显示的声明 permission:

js
{
  "name": "My extension",
  ...
  "permissions": [
    "storage"
  ],
  ...
}

三、使用 ​

他们的使用方法如下:

js
// local
chrome.storage.local.set({ key: value }).then(() => {
  console.log("Value is set");
});

chrome.storage.local.get(["key"]).then((result) => {
  console.log("Value currently is " + result.key);
});

//sync
chrome.storage.sync.set({ key: value }).then(() => {
  console.log("Value is set");
});

chrome.storage.sync.get(["key"]).then((result) => {
  console.log("Value currently is " + result.key);
});

//session
chrome.storage.session.set({ key: value }).then(() => {
  console.log("Value was set");
});

chrome.storage.session.get(["key"]).then((result) => {
  console.log("Value currently is " + result.key);
});

案例 ​

接下来准备一个案例来具体的说明 local 和 session 的使用

第一步:创建一个 chrome 插件项目

结尾有 git 仓库代码,可以直接 down 下来测试

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>popup</h1>
    <select name="type" id="storage-type">
      <option value="local">local</option>
      <option value="session">session</option>
    </select>
    <input type="text" id="storage-value" />
    <button id="storage-btn">存储</button>
    <br />
    <button id="storage-show">数据</button>
    <div id="storage-view"></div>
    <script src="./popup.js"></script>
  </body>
</html>
js
// popup.js
document.getElementById("storage-btn").addEventListener("click", () => {
  const value = document.getElementById("storage-value").value;
  const type = document.getElementById("storage-type").value;

  if (type === "session") {
    chrome.storage.session.set({ session: value }).then(() => {
      console.log("设置local值成功");
    });
  } else {
    chrome.storage.local.set({ local: value }).then(() => {
      console.log("设置session值成功");
    });
  }
});

document.getElementById("storage-show").addEventListener("click", () => {
  chrome.storage.local.get(["local"]).then(({ local }) => {
    chrome.storage.session.get(["session"]).then(({ session }) => {
      document.getElementById("storage-view").innerHTML = `
        <span>local value</span>: ${local} \n
        <span>session value</span>: ${session}
      `;
    });
  });
});

以下是演示视频:

image

接下来我将浏览器关闭,然后我们看看数据状况如何:

image

可以看到 session 的状态已经丢失了,但是 local 的状态依然存在。

onChanged ​

有的时候我们希望监听全局状态的变化,我们可以使用 StorageAPI 提供的 onChanged 方法。

在上面的案例中我们增加一个 background.js,在后台监听。

js
chrome.storage.onChanged.addListener((changes, namespace) => {
  for (let [key, { oldValue, newValue }] of Object.entries(changes)) {
    console.log(
      ` "${namespace}" 区域 有一个属性"${key}" 发生了变化`,
      `旧值为 "${oldValue}",新值为"${newValue}".`
    );
  }
});

image

我们可以看到不同区域的任何一个状态发生变化都可以察觉到,然后在这个函数中我们可以写不同的处理逻辑就好了。

好啦,以上就是本篇 chrome 插件存储系统的所有知识了,大家可以自己也尝试一下!

四、资源 ​

以上的案例位于 chrome-extensions-learn.git 仓库

遵循MIT开源协议