Web WorkerでlocalStorageが使えない理由と代替手段

## はじめに

Web開発をしていると、バックグラウンドで重い処理を行うためにWeb Workerを使用することがあります。しかし、Web Workerには一部の制限があり、その中の1つが`localStorage`へのアクセスができないということです。

この記事では、なぜWeb WorkerでlocalStorageが使えないのか、そしてその代替手段について説明します。

## なぜlocalStorageが使えないのか？

Web Workerで`localStorage`が使えない理由は、以下の2つの要因によります：

1. Web Workerは独自の実行コンテキストを持っています
2. `localStorage`は`window`オブジェクトの一部として実装されています

Web Workerは、メインスレッドとは異なるグローバルスコープ（`WorkerGlobalScope`）で実行されます。このスコープでは、`window`オブジェクトにアクセスすることができません。

そのため、`window.localStorage`にアクセスしようとすると、以下のようなエラーが発生します：

```javascript
// worker.js
console.log(window.localStorage); // ReferenceError: window is not defined
console.log(localStorage);       // ReferenceError: localStorage is not defined
```

## 代替手段：IndexedDB

Web Workerで永続的なデータストレージが必要な場合、IndexedDBを使用することができます。IndexedDBは以下の特徴を持っています：

- Web Workerからアクセス可能
- キー・バリューストアとして機能
- 非同期APIを提供
- より大きなデータ量を扱える

### 基本的な使用例

以下は、IndexedDBを使用してデータを保存・取得する簡単な例です：

```javascript
// worker.js
let db;
const request = indexedDB.open("MyDatabase", 1);

request.onerror = (event) => {
  console.error("Database error: " + event.target.error);
};

request.onsuccess = (event) => {
  db = event.target.result;
  console.log("Database opened successfully");
};

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  const store = db.createObjectStore("MyStore", { keyPath: "id" });
};

// データの保存
function saveData(data) {
  const transaction = db.transaction(["MyStore"], "readwrite");
  const store = transaction.objectStore("MyStore");
  store.put(data);
}

// データの取得
function getData(id) {
  const transaction = db.transaction(["MyStore"], "readonly");
  const store = transaction.objectStore("MyStore");
  const request = store.get(id);
  
  request.onsuccess = (event) => {
    const data = event.target.result;
    self.postMessage({ type: 'getData', data });
  };
}
```

### `idb-keyval`ライブラリの利用

より簡単にIndexedDBを使用したい場合は、`idb-keyval`というライブラリを使用することができます。このライブラリは、`localStorage`に似た簡単なAPIを提供します：

```javascript
import { get, set } from 'idb-keyval';

// データの保存
await set('user', { name: 'John', age: 30 });

// データの取得
const user = await get('user');
```

## トラブルシューティング

Web Workerを使用する際によくある問題と解決方法をまとめます：

1. **ImportScriptsエラー**
   ```javascript
   // エラー: Failed to execute 'importScripts' on 'WorkerGlobalScope'
   importScripts('https://example.com/script.js');
   ```
   - 原因: CORSポリシーやセキュリティ上の制限
   - 解決: 同一オリジンのスクリプトを使用するか、適切なCORSヘッダーを設定

2. **SharedWorkerの接続エラー**
   ```javascript
   // エラー: Failed to construct 'SharedWorker'
   const worker = new SharedWorker('worker.js');
   ```
   - 原因: プライベートブラウジングモードや異なるオリジン間での共有
   - 解決: 同一オリジンで実行されていることを確認

3. **データ転送の問題**
   ```javascript
   // 注意: 構造化クローンアルゴリズムの制限
   worker.postMessage(window); // エラー: window オブジェクトは転送不可
   ```
   - 原因: 転送できないオブジェクトタイプの使用
   - 解決: シリアライズ可能なデータ形式に変換

## まとめ

Web WorkerでlocalStorageが使えない理由は、Web Workerが独自の実行コンテキストを持ち、windowオブジェクトにアクセスできないためです。

代替手段として：
1. IndexedDBを直接使用する
2. `idb-keyval`のような補助ライブラリを使用する

## 参考リンク

- [MDN Web Workers API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)
- [MDN IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)
- [idb-keyval](https://www.npmjs.com/package/idb-keyval)