JavaScriptを有効にしてください

chrome.storage API 更新がすぐに反映されない?

 ·  ☕ 3 分で読めます
Photo by Cleyder Duque from Pexels

Photo by Cleyder Duque from Pexels

chrome.storageは非同期にご注意

chrome.storage API

Chrome拡張機能の開発で何らかのデータを保存したいとき、chrome.storage APIが使えます。
ブラウザのSessionストレージを使う方法もありますが、chrome.storage APIを使えばBackgroundスクリプトやContentスクリプトからでも簡単にストレージにアクセスできるメリットというメリットがあります。

データを更新してから反映されるまでにラグがある

getメソッドでストレージからデータを取得し、データの一部を更新した後にsetメソッドで更新する。
ということがしたかったのですが、ここで想定してなかったことが起こりました。

何かと言うと、
データを更新した後続の処理で、そのデータを再び取得したときに更新したはずの値が変わっていなかったのです。

具体的にはこんなコードでした。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// chrome.storage.localに入っているデータ
// {
//   'key': {
//     'key1': 'value1',
//     'key2': 'value2'
//   }
// }

// key1の値を更新する
chrome.storage.local.get('key', data => {
	data.key.key1 = 'value100';
	chrome.storage.local.set(data, undefined);
})

// key1の値を確認してみる
chrome.storage.local.get('key', data => {
	console.log(data.key.key1);
})

Output

value1

なぜこれが起きるか?

結論は、setメソッドをgetメソッドのコールバックの中で行っていたからでした。
言い換えるとsetメソッドが非同期的に実行されていたからです。

期待する挙動は

  1. getメソッドでデータを取得
  2. setメソッドでデータを更新
  3. getメソッドで更新後の値を取得

ですが、実際には

  1. getメソッドでデータを取得
  2. getメソッドで更新後(のはずの)の値を取得
  3. setメソッドでデータを更新

という順番で実行されています。

対策

対策は、

  1. getメソッドでデータを取得
  2. setメソッドでデータを更新

この部分を同期的に実行してあげることです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// getとsetを同期的に行う関数
const getAndSetInSync = async _ => {
	// storage.getおよびsetを同期的に処理するためPromiseでラップする
	return new Promise(resolve => {
		chrome.storage.local.get('key', data => {
			data.key.key1 = 'value100';
			chrome.storage.local.set(data, resolve); 
			// setが終わった段階でresolveする
		})
	})
}

(async _ => {
	// 関数を同期呼び出しする
	await getAndSetInSync();

	// key1の値を確認してみる
	chrome.storage.local.get('key', data => {
		console.log(data.key.key1);
	})
})()

Output

value100

getとsetをPromiseでラップしてやって、setメソッドのコールバックでPromiseをresolveしてやるのがみそです。

getメソッドを実行した段階では、まだPromiseがresolveされていないのでawait getAndSetInSync()でブロックします。
そしてsetメソッドが実行されてデータが更新されて初めて、Promiseがresolveされ次の処理に進みます。

後続の処理で値を確認してみると、きちんと更新されています。

おわり

JavascriptはWeb用の言語ということもあって、非同期処理が前提になっていてコールバックが頻繁に使われているのかなと思います。

非同期処理は複数のことを並列で行えて便利な一方で、こういうトラップもあるので気をつけないとですね。

共有