Chrome拡張を作ってみた② - 非同期処理ChromeStorage

# はじめに
Chrome拡張を作っていると、アプリとしてデータを永続保存したいケースが出てきます。
manifest version2までであれば非推奨ながらもlocalStorageが使えていましたが、Version3からはこれが禁止され、ChromeStorageを使う必要が出てきました。

本稿では、manifest Version3を用いたstorageへのデータ保存について実践します。

# localStorageとChromeStorageの差
どちらもブラウザに対して永続的にデータを保持させる仕組みです。

実装する上で大きな違いは、
localstorageが同期処理による読み書きですが、
ChromeStorageは非同期処理となります。

以下がそれぞれのstorageに対する読み書きのサンプルコードです。

``` javascript:localstorage
// 同期処理
// 書き込み
localStorage.setItem("lastAccessUrl", "URL");
console.log('success');

// 読み込み
const lau = localStorage.getItem("lastAccessUrl");
console.log(lau);

// 同期処理のため通常の関数呼び出しの意識で利用可能
```

``` javascript:ChromeStorage
// 非同期処理
// 書き込み
chrome.storage.local.set( {"lastAccessUrl": "URL" } ).then(() => {
  // set後のコールバックで、事後処理を行う
  console.log('success');
});

// 読み込み
chrome.storage.local.get("lastAccessUrl").then((data) => {
  // get後のコールバックで、事後処理を行う
  const lau = data.lastAccessUrl;
  console.log(lau);
});
```

# 本稿の作成物
最終アクセスURLをstorageに記録し、ブラウザを開いた際にコンソールへ表示します。

# 登場人物
本稿で必要なファイルは二つのみです。

①manifest.json
②content.js

# 配置
関連記事と同様の構成を取っています。
本拡張の保存先を「sample2」として以下の図のようにファイルを配置します。
※ manifest.json および content.js はUTF-8で保存してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/707c07b9-4575-488d-8cfd-23cfe720985e.png)


# manifest.json
このAddonは全てのサイトを開いた際に動作させるため、
matchesの指定を\<all_urls>としています。
\<all_urls>は、全てのサイトを示すワイルドカードとして利用できます。

また、Storageを使うため、permissionsでstorageを指定してアクセス許可を与えています。

``` json:manifest.json
{
  "manifest_version": 3,
  "name": "Qiita投稿用サンプル2",
  "description": "最終アクセスURLとtitleをchromeStorageへ保存します",
  "version": "0.1",
  "content_scripts": [
    {
      "js": [
        "scripts/content.js"
      ],
      "matches": [
        "<all_urls>"
      ]
    }
  ],
  "permissions": [
    "storage"
  ]
}
```

# content.js
サイトアクセス時にURLとサイトタイトルを取得し、ChromeStorage上へ以下のようなjson形式で保存します。

``` json:chrome.storage
{
  "lastAccess": {
    "url": "URL",
    "title": "site title"
  }
}
```


``` javascript:content.js
// URLとサイトタイトルを取得
const url = location.href;
const title = document.title;

var data = {
  "lastAccess": {
    "url": url,
    "title": title
  }
}

// chromeStorageへ書き込む
chrome.storage.local.set(data).then(() => {
  // 書き込んだ内容を確認するためコンソールログへ出力
  chrome.storage.local.get( "lastAccess" ).then( (data) => {
    console.log(data.lastAccess);
  });
});
```

ChromeのDevToolsのConsoleから確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/2ae567eb-b929-5c5e-5330-dda1566664c4.png)


無事書き込みが確認できました。

コードを以下のように変更し、Consoleに前回開いたサイトURLとサイトタイトルを表示後、現在のサイト情報を保存するようにします。

```javascript:content.js
console.log("前回開いていたサイトはこちら");
chrome.storage.local.get( "lastAccess" ).then( (data) => {
  console.log(data.lastAccess);
});


console.log("現在のアクセスサイト情報を上書きする");
// URLとサイトタイトルを取得
const url = location.href;
const title = document.title;

var data = {
  "lastAccess": {
    "url": url,
    "title": title
  }
}

// ChromeStorageへ書き込む
chrome.storage.local.set(data).then(() => {
  console.log("書き込み完了");
});
```

Qiitaへアクセス後、次のサイトを開いた際のログが以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/1d9c0d51-8146-f5c9-3d9f-b048773a95df.png)

「chrome.storage.local.get」の呼び出しが非同期であるため、
そのコールバックでstorage内の値をconsoleに表示していますが、その実行よりも先に「現在のアクセスサイト情報を上書きする」が表示されています。


同期処理のように順序よく処理させるには以下のような工夫が必要です。

```javascript:content.js
console.log("前回開いていたサイトはこちら");
chrome.storage.local.get( "lastAccess" ).then( (data) => {
  console.log(data.lastAccess);

  // コールバック内でsetを行う
  console.log("現在のアクセスサイト情報を上書きする");
  // URLとサイトタイトルを取得
  const url = location.href;
  const title = document.title;

  var data = {
    "lastAccess": {
      "url": url,
      "title": title
    }
  }

  // ChromeStorageへ書き込む
  chrome.storage.local.set(data).then(() => {
    console.log("書き込み完了");
  });
});
```

無事想定した順序になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2517800/e6ace2f4-97e8-cb09-dc79-fa28d0eb3ec2.png)


# おわりに
localStorageを用いるJSからの変更は、この非同期挙動がハードルとなることが多いようですが、非同期であるが故のメリットもあります。
正しく理解して使っていこうと思います。

# 関連記事
https://qiita.com/ydclab_0007/items/c1d235b524e8223fbf91