Pembacaan format selektif: Default yang lebih baik untuk Async Clipboard API

Prashant Singh
Prashant Singh

Dipublikasikan: 3 Juli 2026

Jika Anda pernah menggunakan editor dokumen, aplikasi spreadsheet, atau aplikasi apa pun yang menempelkan konten dari papan klip sebagai interaksi utama, Anda akan mengetahui ekspektasi pengguna: penempelan harus terasa instan.

Sayangnya, dalam banyak kasus, aplikasi web membaca lebih banyak data papan klip daripada yang diperlukan, yang dapat membuat penempelan konten terasa lebih lambat dari seharusnya, membuang siklus CPU, dan menggunakan memori untuk data yang tidak pernah diperlukan aplikasi.

Pembacaan format selektif mengatasi masalah performa ini dengan mengubah Async Clipboard API agar lebih memenuhi ekspektasi pengguna dan memberikan apa yang dibutuhkan developer—hanya membaca format yang benar-benar diperlukan aplikasi.

Masalah: Membaca semua format data di awal

Saat pengguna menyalin dari aplikasi apa pun—misalnya, Excel, Google Dokumen, atau Photoshop—aplikasi biasanya menulis beberapa representasi data yang sama ke papan klip sistem: teks biasa, HTML, gambar, dan terkadang format kustom. Aplikasi web yang membaca data (saat pengguna menempel dari papan klip) jarang memerlukan semua representasi ini. Editor spreadsheet mungkin menginginkan HTML. Editor teks mungkin ingin mengekspos perintah "tempel sebagai teks biasa". Editor kode mungkin hanya menginginkan teks dan tidak ada yang lain.

Hingga saat ini, navigator.clipboard.read() mengambil setiap representasi data yang tersedia dari papan klip sistem, menjalankan pembersihan (yang dapat memerlukan waktu, terutama dengan payload HTML atau gambar yang besar), dan menyimpan byte dalam memori, bahkan untuk format yang tidak akan pernah digunakan aplikasi. Semakin besar payload yang tidak digunakan, semakin lama pengguna harus menunggu, dan semakin banyak memori yang digunakan tab, tepat saat responsivitas penempelan paling penting.

Solusi: Hanya menghitung, lalu membaca sesuai permintaan

Dari Chrome dan Edge 149, ClipboardItem objek yang ditampilkan oleh metode navigator.clipboard.read() hanya menjelaskan apa yang ada di papan klip, bukan memberikan akses ke data secara langsung. Byte sebenarnya untuk format tertentu hanya dibaca dari papan klip saat Anda memanggil ClipboardItem.getType(mimeType). Tampilan API tidak berubah. Kode yang Anda tulis kemarin masih berfungsi hingga saat ini, sehingga memberikan manfaat performa langsung:

// 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.
}

Manfaat performa lainnya di sini adalah caching otomatis. Memanggil getType('text/html') dua kali pada ClipboardItem yang sama hanya membaca dari papan klip sistem satu kali dan menampilkan Blob yang di-cache pada panggilan kedua.

Manfaat

Latensi. Tugas yang perlu dilakukan saat navigator.clipboard.read() dipanggil, seperti menyalin byte di seluruh proses, membersihkan HTML, atau mendekode gambar, kini hanya terjadi untuk format yang benar-benar diperlukan aplikasi Anda. Aplikasi yang hanya membaca satu format akan mendapatkan sebagian besar penghematan. Semakin besar format yang Anda lewati, semakin besar keuntungannya. HTML paling diuntungkan karena pembersihan HTML mahal.

Memori. Sebelumnya, memanggil navigator.clipboard.read() saat papan klip menyimpan gambar 50 MB berarti 50 MB harus digunakan dalam memori perender halaman web hingga ClipboardItem dirilis, meskipun aplikasi hanya memerlukan representasi text/plain dari data. Sekarang, hanya format yang dibaca aplikasi Anda saat memanggil ClipboardItem.getType() yang menggunakan memori dalam proses perender. Untuk aplikasi yang sering menempel, seperti editor dokumen, komposer email, atau alat desain, hal ini akan mengurangi penggunaan memori secara signifikan selama penempelan, terutama pada sesi multi-tab saat beberapa editor mungkin membaca papan klip secara paralel.

Tidak ada keikutsertaan. Setiap situs di web akan mendapatkan manfaat ini secara otomatis. Anda tidak perlu memigrasikan kode atau kode gerbang di balik logika deteksi fitur.

Satu perubahan perilaku yang perlu diperhatikan

Membaca data nanti akan memperkenalkan sedikit perubahan perilaku: objek ClipboardItem bukan lagi snapshot papan klip yang dibekukan pada saat panggilan ke navigator.clipboard.read() diselesaikan.

Saat read() dipanggil dan menampilkan ClipboardItem, item ini hanya handle lambat ke data di papan klip sistem. Jika konten papan klip berubah antara panggilan ke read() dan panggilan berikutnya ke getType(), panggilan tersebut akan ditolak dengan InvalidStateError. Hal ini berlaku bahkan untuk format yang sebelumnya berhasil Anda baca di ClipboardItem yang sama.

// 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');

Hal ini terjadi karena menampilkan data yang tidak lagi mencerminkan papan klip akan membingungkan dan menyebabkan masalah yang sulit di-debug.

Dalam praktiknya, perubahan ini tidak terlihat oleh sebagian besar kode, karena aplikasi biasanya memanggil read() dan getType() secara berurutan di dalam pengendali penempelan yang sama. Namun, Anda mungkin ingin mengawasi kasus saat Anda memiliki kode yang menyimpan ClipboardItem di seluruh batas asinkron.

Berikut adalah contoh saat perubahan ini dapat menjadi masalah: menyimpan cache objek ClipboardItem di window, menampilkannya di UI histori papan klip, atau menunggu interaksi pengguna sebelum memanggil getType(). Untuk menghindari masalah dengan skenario seperti ini:

  • Gabungkan panggilan getType() dalam blok try / catch, dan perlakukan InvalidStateError sebagai sinyal bahwa papan klip telah berpindah dan kode harus dibaca lagi.
  • Jika Anda perlu menyimpan data papan klip, salin Blob ke dalam struktur Anda sendiri segera setelah Anda getType(). Jangan perlakukan ClipboardItem sebagai penyimpanan jangka panjang.
  • Gunakan peristiwa clipboardChange untuk secara proaktif membatalkan handle yang tidak berlaku.

Standar dan dukungan browser

Pembacaan format selektif adalah perubahan spesifikasi Clipboard API yang didorong oleh Web Editing Working Group dan tim platform web Microsoft Edge.

Safari juga mendukung perilaku ini, dan Firefox telah menunjukkan a posisi standar yang positif dan niat untuk menyelaraskan.

Peningkatan performa dan interoperabilitas yang tenang, tetapi bermakna untuk Clipboard API, dengan Chromium yang kini menyatu ke model yang sama.