選択的フォーマット読み取り: Async Clipboard API のデフォルトの改善

Prashant Singh
Prashant Singh

公開日: 2026 年 7 月 3 日

ドキュメント エディタ、スプレッドシート アプリ、クリップボードからコンテンツを貼り付けることが主な操作となるアプリを使用したことがある方なら、ユーザーが期待する動作をご存じでしょう。貼り付けは瞬時に行われるべきです。

残念ながら、多くのケースでウェブアプリは必要以上のクリップボード データを読み取ります。これにより、コンテンツの貼り付けが本来よりも遅く感じられ、CPU サイクルが無駄になり、アプリが不要なデータにメモリが使用されます。

選択的フォーマット読み取り は、 Async Clipboard API を変更してユーザーの期待に応え、アプリが実際に必要とするフォーマットのみを読み取ることで、このパフォーマンスの問題に対処します。

問題: すべてのデータ形式を事前に読み取る

ユーザーが Excel、Google ドキュメント、Photoshop などのアプリからコピーすると、通常、アプリは同じデータの複数の表現をシステム クリップボードに書き込みます。プレーン テキスト、HTML、画像、カスタム形式などです。ユーザーがクリップボードから貼り付けるときにデータを読み取るウェブアプリは、これらの表現をすべて必要とすることはほとんどありません。スプレッドシート エディタでは HTML が必要になることがあります。テキスト エディタでは、「プレーン テキストとして貼り付け」コマンドを表示することがあります。コード エディタでは、テキストのみが必要で、それ以外は必要ありません。

これまで、 navigator.clipboard.read() は、システム クリップボードからデータの利用可能な表現をすべてフェッチし、サニタイズを実行(特に大きな HTML ペイロードや 画像ペイロードの場合は時間がかかることがあります)し、アプリが使用しないフォーマットでもバイトをメモリに保持していました。未使用のペイロードが大きいほど、ユーザーは待機時間が長くなり、貼り付けの応答性が最も重要なときにタブが消費するメモリが増加します。

解決策: 列挙のみを行い、オンデマンドで読み取る

Chrome と Edge 149 以降では、 ClipboardItem メソッドから返されるオブジェクトは、データをすぐに取得するのではなく、 クリップボードの内容のみを記述します。navigator.clipboard.read()特定のフォーマットの実際のバイトは、 クリップボードから読み取られるのは、 ClipboardItem.getType(mimeType) を呼び出した場合のみです。 API サーフェスは変更されていません。昨日作成したコードは今日も引き続き機能し、パフォーマンスがすぐに向上します。

// Enumerate the available MIME types.
// No payload is fetched yet.
const items = await navigator.clipboard.read();

for (const item of items) {
  if (item.types.includes('text/html')) {
    // Only read the HTML data.
    // The data is fetched (and sanitized) here only.
     const blob = await item.getType('text/html');
     useThePastedHtml(await blob.text());
     break;
   }

   // text/plain, image/png, or any other custom formats
   // stored in the clipboard are never read.
}

もう一つのパフォーマンス上のメリットは、キャッシュが自動的に行われることです。同じ ClipboardItemgetType('text/html') を 2 回呼び出すと、システム クリップボードから 1 回だけ読み取り、2 回目の呼び出しでキャッシュされた Blob を返します。

メリット

レイテンシ。navigator.clipboard.read() が呼び出されたときに必要だった処理(プロセス間のバイトのコピー、HTML のサニタイズ、画像のデコードなど)は、アプリが実際に必要とするフォーマットに対してのみ行われるようになりました。単一のフォーマットのみを読み取るアプリでは、ほとんどの保存が可能です。スキップするフォーマットが多いほど、メリットが大きくなります。HTML のサニタイズはコストが高いため、HTML が最もメリットがあります。

メモリ。以前は、クリップボードに 50 MB の画像が保持されているときに navigator.clipboard.read() を呼び出すと、アプリがデータの text/plain 表現のみを必要とする場合でも、ClipboardItem が解放されるまでウェブページのレンダラ メモリで 50 MB を使用する必要がありました。現在では、ClipboardItem.getType() を呼び出すときにアプリが読み取るフォーマットのみが、レンダラ プロセスでメモリを使用します。ドキュメント エディタ、メール作成ツール、デザインツールなど、貼り付けが一般的なアプリでは、貼り付け時のメモリ使用量が大幅に削減されます。特に、複数のエディタがクリップボードを並行して読み取る可能性があるマルチタブ セッションでは、メモリ使用量が大幅に削減されます。

オプトインは不要。ウェブ上のすべてのサイトで、これらのメリットが自動的に得られます。コードを移行したり、機能検出ロジックの背後にコードをゲートしたりする必要はありません。

注意すべき動作の変更点

後でデータを読み取ると、動作がわずかに変更されます。ClipboardItem オブジェクトは、navigator.clipboard.read() が解決した時点のクリップボードのフリーズ スナップショットではなくなりました。

read() が呼び出されて ClipboardItem を返すと、このアイテムはシステム クリップボード内のデータへの遅延ハンドル にすぎません。read() の呼び出しと後続の getType() の呼び出しの間にクリップボードの内容が変更された場合、その呼び出しは InvalidStateError で拒否されます。これは、以前に同じ ClipboardItem で正常に読み取ったフォーマットでも当てはまります。

// Read from the clipboard.
const items = await navigator.clipboard.read();
// Get the first ClipboardItem.
const item = items[0];

// Actually fetch the data now, which works fine.
const text = await item.getType('text/plain');

// The user writes something new to the clipboard
// by copying from another app, or your own code writes to
// the clipboard again.
await navigator.clipboard.writeText('something new');

// Fetching the data from the earlier ClipboardItem
// rejects with InvalidStateError, because the contents
// of the clipboard changed.
const html = await item.getType('text/html');

これは、クリップボードを反映しなくなったデータを返すと、混乱を招き、デバッグが困難な問題につながるためです。

実際には、アプリは通常、同じ貼り付けハンドラ内で read()getType() を連続して呼び出すため、ほとんどのコードで変更は表示されません。ただし、非同期境界を越えて ClipboardItem を保持するコードがある場合は、注意が必要です。

この変更が問題になる可能性がある例を次に示します。windowClipboardItem オブジェクトをキャッシュする、クリップボード履歴 UI に表示する、getType() を呼び出す前にユーザー操作を待機する。このようなシナリオで問題が発生しないようにするには、次の操作を行います。

  • getType() 呼び出しを try / catch ブロックでラップし、InvalidStateError をクリップボードが移動したことを示すシグナルとして扱い、コードを再度読み取るようにします。
  • クリップボード データを保持する必要がある場合は、getType() を取得したらすぐに Blob を独自の構造にコピーします。ClipboardItem を長期保存として扱わないでください。
  • clipboardChange イベントを使用して、古いハンドルを事前に無効にします。

標準とブラウザのサポート

選択的フォーマット読み取りは、Clipboard APIs specification changeは、Web Editing Working Group と Microsoft Edge ウェブ プラットフォーム チームが推進する変更です。

Safari もこの動作をサポートしており、Firefox は標準化に 前向きな姿勢 を示し、対応する意向を示しています。

Chromium が同じモデルに収束し、Clipboard API のパフォーマンスと相互運用性が静かに、しかし有意義に向上しています。