# 通知設計書 22-onError

## 概要

本ドキュメントは、Three.jsのLoadingManagerにおける`onError`コールバック通知の仕様を定義する。`onError`は、LoadingManagerが管理するアイテムの読み込み中にエラーが発生した際に呼び出されるコールバック関数である。

### 本通知の処理概要

`onError`コールバックは、LoadingManagerを使用するローダーがリソースの読み込みに失敗した際に発火する通知である。これにより、アプリケーションはエラーを適切にハンドリングし、ユーザーへのフィードバックやフォールバック処理を実行できる。

**業務上の目的・背景**：WebGLアプリケーションでは、ネットワークエラー、CORSエラー、ファイル不在など様々な理由でリソース読み込みが失敗する可能性がある。`onError`コールバックは、これらのエラーを一元的に検知し、適切なエラーハンドリング（代替リソースの読み込み、エラーメッセージの表示など）を実装するための仕組みを提供する。

**通知の送信タイミング**：ローダーが`manager.itemError(url)`を呼び出した時点で発火する。これは通常、fetch APIがエラーを返した場合、HTTPステータスコードが失敗を示す場合、またはレスポンスのパースに失敗した場合に発生する。

**通知の受信者**：LoadingManagerインスタンスを作成した開発者、またはDefaultLoadingManagerを使用しているアプリケーションコード。コールバック関数として登録された任意の関数が受信者となる。

**通知内容の概要**：エラーが発生したリソースのURL（文字列）が引数として渡される。これにより、どのリソースの読み込みに失敗したかを特定できる。

**期待されるアクション**：受信者は、エラーログの記録、ユーザーへのエラー通知、代替リソースの読み込み、リトライ処理の実行などのアクションを実行することが期待される。

## 通知種別

コールバック関数（Callback Notification）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 高 |
| リトライ | 無（リトライロジックは呼び出し側で実装） |

### 送信先決定ロジック

LoadingManagerインスタンスの`onError`プロパティに設定された関数が送信先となる。コンストラクタの第三引数、または直接プロパティ代入で設定可能。

```javascript
// コンストラクタで設定
const manager = new LoadingManager(onLoadCallback, onProgressCallback, onErrorCallback);

// プロパティ代入で設定
manager.onError = (url) => console.error('Error loading:', url);
```

## 通知テンプレート

### コールバック形式

| 項目 | 内容 |
|-----|------|
| 関数シグネチャ | `(url: string) => void` |
| 引数 | url - エラーが発生したリソースのURL |
| 戻り値 | なし |

### 本文テンプレート

```javascript
// 典型的な使用例
const manager = new LoadingManager();
manager.onError = function(url) {
    console.error('Error loading resource:', url);
    // ユーザーへの通知
    showErrorMessage('リソースの読み込みに失敗しました: ' + url);
    // 代替リソースの読み込み（オプション）
    loadFallbackResource(url);
};
```

### 添付ファイル

該当なし（コールバック通知のため）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| url | エラーが発生したリソースのURL | itemError()メソッドの引数 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 内部イベント | itemError()呼び出し | onErrorが定義済み | ローダーがエラーを検知した場合 |
| HTTPエラー | fetchのレスポンスエラー | HTTPステータス 4xx/5xx | サーバーからエラーレスポンスを受信 |
| ネットワークエラー | fetch例外 | ネットワーク接続失敗 | リクエスト自体が失敗 |
| パースエラー | レスポンス処理失敗 | データ形式不正 | JSON/ArrayBuffer等への変換失敗 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| onErrorがundefined | コールバックが設定されていない場合は送信されない |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[Loaderがリソース読み込み開始] --> B[fetch request]
    B --> C{レスポンス受信?}
    C -->|Yes| D{HTTPステータス OK?}
    C -->|No| E[ネットワークエラー]
    D -->|Yes| F[データ処理]
    D -->|No| G[HTTPError生成]
    F --> H{パース成功?}
    H -->|Yes| I[正常完了]
    H -->|No| J[パースエラー]
    E --> K[catch節でエラー処理]
    G --> K
    J --> K
    K --> L[個別onErrorコールバック実行]
    L --> M[manager.itemError url 呼び出し]
    M --> N{manager.onErrorが定義済み?}
    N -->|Yes| O[manager.onError url 実行]
    N -->|No| P[終了]
    O --> P
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（Three.jsはクライアントサイドライブラリであり、データベースを使用しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| HTTPエラー | サーバーが4xx/5xxを返却 | URLの確認、サーバー状態の確認 |
| ネットワークエラー | 接続タイムアウト、DNS解決失敗等 | ネットワーク状態の確認、リトライ |
| CORSエラー | クロスオリジンリクエストがブロック | サーバーのCORS設定確認 |
| パースエラー | レスポンスデータの形式不正 | ファイルの整合性確認 |
| コールバック内例外 | onError関数内で例外発生 | 呼び出し元に例外が伝播 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（LoadingManager自体はリトライしない） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

注: リトライロジックが必要な場合は、onErrorコールバック内で実装する必要がある。

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（クライアントサイドで即時実行）

## セキュリティ考慮事項

- URLにはクエリパラメータとして認証トークンが含まれる可能性があるため、エラーログ出力時は注意が必要
- エラーメッセージをユーザーに表示する際は、内部パスや機密情報が露出しないよう配慮すること
- サードパーティリソースの読み込みエラーは、CORS設定の確認が必要

## 備考

- `onError`はLoadingManagerレベルのコールバックであり、個別のローダーにも`onError`コールバックを設定可能
- FileLoaderでは、個別の`onError`コールバックが先に実行され、その後`manager.itemError(url)`が呼ばれる
- エラーが発生しても`itemEnd()`は呼ばれるため、`onLoad`は全アイテム完了後に正常に発火する
- AbortController.abort()による中断もエラーとして扱われる

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

LoadingManagerのonErrorプロパティと関連メソッドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | LoadingManager.js | `src/loaders/LoadingManager.js` | onErrorプロパティの定義とitemError()メソッドを確認 |

**読解のコツ**: onErrorはコンストラクタの第三引数で受け取り、プロパティとして保持される（70行目）。itemError()メソッドがこれを呼び出す。

#### Step 2: エントリーポイントを理解する

itemError()メソッドがonErrorを呼び出す仕組みを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | LoadingManager.js | `src/loaders/LoadingManager.js` | itemError()メソッドの実装を確認 |

**主要処理フロー**:
1. **140行目**: `itemError`関数定義開始
2. **142行目**: `if (scope.onError !== undefined)` - onErrorが定義されているか確認
3. **144行目**: `scope.onError(url)` - urlを引数としてonErrorを実行

#### Step 3: 呼び出し元（FileLoader）を理解する

FileLoaderがどのようなエラー時にitemError()を呼び出すかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FileLoader.js | `src/loaders/FileLoader.js` | catch節でのエラー処理を確認 |

**主要処理フロー**:
- **289-314行目**: `.catch(err => {...})` - fetchエラーのハンドリング
- **305-309行目**: 個別のonErrorコールバックを全て実行
- **312行目**: `this.manager.itemError(url)` - LoadingManagerのonErrorを発火

#### Step 4: HttpErrorクラスを理解する

FileLoaderで定義されているHttpErrorクラスの構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | FileLoader.js | `src/loaders/FileLoader.js` | HttpErrorクラスの定義（7-16行目） |

**主要処理フロー**:
- **7行目**: `class HttpError extends Error` - Errorを拡張
- **11行目**: `this.response = response` - HTTPレスポンスを保持
- **221行目**: `throw new HttpError(...)` - 非成功ステータス時にスロー

### プログラム呼び出し階層図

```
FileLoader.load(url)
    │
    ├─ fetch(req)                  [FileLoader.js:142]
    │
    └─ .catch(err => {...})        [FileLoader.js:289]
           │
           ├─ 個別onErrorコールバック実行
           │      for (callback.onError)  [FileLoader.js:305-309]
           │
           └─ manager.itemError(url)      [FileLoader.js:312]
                  │
                  └─ if (onError !== undefined)
                         └─ onError(url)  ★この通知
                              [LoadingManager.js:144]
```

### データフロー図

```
[入力]                    [処理]                         [出力]

リソースURL ───────▶ FileLoader.load() ───────────▶ エラー発生
                           │
                           │ fetch失敗
                           ▼
                    ┌──────────────────┐
                    │ .catch(err)      │
                    │ HTTPError/Network│
                    └──────────────────┘
                           │
                           │ 個別onError実行
                           ▼
                    ┌──────────────────┐
                    │callback.onError()│
                    └──────────────────┘
                           │
                           │ manager.itemError(url)
                           ▼
                    ┌──────────────────┐
                    │manager.onError() │ ───────────▶ アプリケーション
                    │     (url)        │              （エラーハンドリング）
                    └──────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| LoadingManager.js | `src/loaders/LoadingManager.js` | ソース | onErrorコールバックの定義とitemError()メソッド |
| FileLoader.js | `src/loaders/FileLoader.js` | ソース | エラー発生時のitemError()呼び出し実装 |
| Loader.js | `src/loaders/Loader.js` | ソース | 基底クラス。onErrorCallbackの型定義を含む |
| ImageLoader.js | `src/loaders/ImageLoader.js` | ソース | 画像読み込みエラー時のハンドリング例 |
| TextureLoader.js | `src/loaders/TextureLoader.js` | ソース | テクスチャ読み込みエラー時のハンドリング例 |
| Cache.js | `src/loaders/Cache.js` | ソース | キャッシュ機構。エラー時はキャッシュされない |
| LoadingManager.tests.js | `test/unit/src/loaders/LoadingManager.tests.js` | テスト | LoadingManagerの単体テスト |
