`<wa-select>` と `<wa-combobox>` の大量オプション時のパフォーマンス改善

shoelace-style/webawesome

<wa-select><wa-combobox><wa-option> の3コンポーネントに対して、スロット変更のバッチ処理、オプションのキャッシュ、チェックアイコンの遅延レンダリングを導入し、大量オプション時のパフォーマンスを改善しました。

背景

大量の <wa-option> を持つ <wa-select><wa-combobox> で、パフォーマンス上の問題が報告されていました。この問題は discussions/2197 で議論されており、オプションが追加・変更されるたびにラベル再計算やオプション一覧の再収集が同期的に実行される設計が原因でした。

従来の実装では、<wa-option>connectedCallback でラベルの初期化を即時実行し、スロット内容が変わるたびに updateDefaultLabel() を同期呼び出していました。また <wa-select> はスロット変更のたびにすべてのオプションを再収集していたため、オプション数が増えるほどコストが線形に積み重なる構造でした。

これらの問題を、キャッシュ・遅延評価・バッチ処理という3つのアプローチで解消したのが本PRです。

技術的な変更

<wa-option>: ダーティフラグによる遅延ラベル計算

defaultLabel をリアクティブな @state() プロパティからゲッターに変換し、ダーティフラグ (isDefaultLabelDirty) で再計算のタイミングを制御するようになりました。

変更前:

@state() defaultLabel = '';

connectedCallback() {
  super.connectedCallback();
  // ...
  this.updateDefaultLabel();
}

private handleDefaultSlotChange() {
  // Tell the controller to update the label
  this.updateDefaultLabel();
  // ...
}

変更後:

private cachedDefaultLabel = '';
private isDefaultLabelDirty = true;

get defaultLabel(): string {
  if (this.isDefaultLabelDirty || !this.cachedDefaultLabel) {
    this.updateDefaultLabel();
  }
  return this.cachedDefaultLabel;
}

private handleDefaultSlotChange() {
  // Mark the default label as needing recalculation
  this.isDefaultLabelDirty = true;
  // ...
}

connectedCallback での即時 updateDefaultLabel() 呼び出しも削除されました。スロット内容が変化した際も即座に再計算するのではなく、isDefaultLabelDirty = true とマークするだけになり、実際の計算は defaultLabel が読み取られるまで遅延されます。

<wa-select>: オプションキャッシュとスロット変更のバッチ処理

<wa-select> には cachedOptionsslotChangePending の2つのフィールドが追加されました。

private cachedOptions: WaOption[] | null = null;
private slotChangePending = false;

getAllOptions() の結果を cachedOptions にキャッシュすることで、スロット変更がない限り同一の配列を返し、オプション一覧の再収集コストを削減しています。slotChangePending フラグはスロット変更イベントをバッチ処理するために使われており、複数のオプションが短時間に追加された場合でも processSlotChange() の実行を1回にまとめます。

また optionValues の再構築ロジックも最適化されました。従来は毎回 value == null を判定して全オプションを走査していましたが、変更後は optionValues === undefined のときのみ再構築し、キャッシュが有効な間は再走査をスキップします。

初期化処理も変更されており、connectedCallback では handleDefaultSlotChange の代わりに processSlotChange を直接呼び出すようになりました。コード中のコメントによれば、初回のセットアップを同期的に実行するためであり、その後のオプション追加は handleDefaultSlotChange 経由でバッチ処理されます。

設計判断

遅延評価とダーティフラグの組み合わせ が採用された点が設計上の核心です。defaultLabel をゲッターに変換することで、値が必要になるまで計算を先送りにできます。これは特に、オプションが画面外にある場合や、ドロップダウンが開いていない場合に無駄な計算を避ける効果があります。

バッチ処理 の導入は、Webコンポーネントにおける典型的な最適化パターンです。DOMへのオプション追加は複数回まとめて行われることが多く、各追加に対して即時処理するよりも、一定期間の変更を集約してから処理する方がコスト効率が高くなります。slotChangePending フラグによるデバウンス的なアプローチがこの目的を果たしています。

これらの変更はすべて内部実装の変更であり、コンポーネントの公開APIは変わりません。既存の利用コードへの影響なく、パフォーマンス特性のみが改善されます。

まとめ

本PRは、ラベル計算の遅延評価・オプション一覧のキャッシュ・スロット変更のバッチ処理という3つの最適化をそれぞれのコンポーネントに適切に配置することで、大量オプション時のパフォーマンスボトルネックを解消しています。公開APIを変えずに内部実装のみを最適化する手法は、コンポーネントライブラリの後方互換性を保ちながら性能を向上させる堅実なアプローチといえます。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
48a11f11

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

「総論→各論→結論」の構成が明確で、リード文、背景、技術詳細、設計判断、まとめの各要素が適切に配置されています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライトやGitHubへのリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

遅延評価やダーティフラグといった専門的な内容を、エンジニア読者向けに適切なレベルで解説しています。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクション・各パラグラフが論理的に構成されており、トピックセンテンスが明確で可読性が高いです。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内のコードブロックは、提供されたDiffの内容を正確に引用しており、ファイルパスも一致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「ダーティフラグ」「バッチ処理」「遅延評価」などの技術用語が、文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

コード変更の意図や影響に関する説明は、Diffの内容と整合しており、技術的に正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事の主張はすべてPRのDescriptionやDiff内のコードで裏付けられており、ハルシネーションは見られません。PRのDescriptionにある「lazily rendering check icons」というDiffにない情報に触れず、Diffにある事実のみを記述している点も正確です。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#2203)やDiscussion番号(2197)、コード内の変数名などが正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルはPRの主題を正確に反映しており、内容を的確に要約しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PR情報に含まれない外部の知識(バージョン情報、リリース予定など)の追記はなく、提供された情報に忠実です。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「従来の実装では」「変更後は」といった時間表現が、PRによる変更の前後関係を正しく記述しています。