Opublikowano: 3 lipca 2026 r.
Jeśli kiedykolwiek używałeś edytora dokumentów, arkusza kalkulacyjnego lub innej aplikacji, w której wklejanie treści ze schowka jest podstawową interakcją, wiesz, czego oczekują użytkownicy: wklejanie powinno być natychmiastowe.
Niestety w wielu przypadkach aplikacje internetowe odczytują więcej danych ze schowka, niż potrzebują, co może sprawić, że wklejanie treści będzie wolniejsze niż powinno, marnuje cykle procesora i wykorzystuje pamięć na dane, których aplikacja nigdy nie potrzebuje.
Selektywne odczytywanie formatów rozwiązuje ten problem z wydajnością, modyfikując interfejs Async Clipboard API aby lepiej spełniać oczekiwania użytkowników i zapewniać deweloperom to, czego potrzebują – odczytywanie tylko tych formatów, których aplikacja faktycznie potrzebuje.
Problem: odczytywanie wszystkich formatów danych z góry
Gdy użytkownik kopiuje dane z dowolnej aplikacji – np. Excela, Dokumentów Google lub Photoshopa – aplikacja zwykle zapisuje w schowku systemowym kilka reprezentacji tych samych danych: zwykły tekst, HTML, obraz i czasami formaty niestandardowe. Aplikacja internetowa, która odczytuje dane (gdy użytkownik wkleja je ze schowka), rzadko potrzebuje wszystkich tych reprezentacji. Edytor arkuszy kalkulacyjnych może potrzebować kodu HTML. Edytor tekstu może chcieć udostępnić polecenie „wklej jako zwykły tekst”. Edytor kodu może potrzebować tylko tekstu.
Do tej pory,
navigator.clipboard.read()
pobierała każdą dostępną reprezentację danych ze schowka systemowego, przeprowadzała czyszczenie (co może zająć trochę czasu, zwłaszcza w przypadku dużych ładunków HTML lub
obrazów) i przechowywała bajty w pamięci, nawet w przypadku formatów, których aplikacja
nigdy nie użyje. Im większy nieużywany ładunek, tym dłużej użytkownik musiał czekać i tym więcej pamięci zużywała karta, czyli wtedy, gdy szybkość wklejania jest najważniejsza.
Rozwiązanie: tylko wyliczanie, a potem odczytywanie na żądanie
W Chrome i Edge 149,
ClipboardItem
obiekty zwracane przez metodę navigator.clipboard.read() opisują tylko
to, co znajduje się w schowku, zamiast od razu udostępniać dane. Rzeczywiste bajty danego formatu są odczytywane ze schowka tylko wtedy, gdy wywołasz funkcję
ClipboardItem.getType(mimeType).
Powierzchnia interfejsu API pozostaje bez zmian. Kod napisany wczoraj nadal działa, co daje natychmiastowe korzyści w zakresie wydajności:
// 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.
}
Kolejną korzyścią w zakresie wydajności jest automatyczne buforowanie. Dwukrotne wywołanie funkcji
getType('text/html') w tym samym obiekcie ClipboardItem powoduje odczytanie ze schowka systemowego
tylko raz, a przy drugim wywołaniu zwraca zbuforowany obiekt Blob.
Zalety
Opóźnienie. Prace, które trzeba było wykonać po wywołaniu funkcji navigator.clipboard.read(), takie jak kopiowanie bajtów między procesami, czyszczenie kodu HTML czy dekodowanie obrazów, są teraz wykonywane tylko w przypadku formatów, których aplikacja faktycznie potrzebuje. Najwięcej oszczędzają aplikacje, które odczytują tylko jeden format. Im większe formaty pomijasz, tym większe oszczędności. Największe korzyści przynosi to w przypadku kodu HTML, ponieważ jego czyszczenie jest kosztowne.
Pamięć. Wcześniej wywołanie funkcji navigator.clipboard.read() , gdy w schowku znajdował się obraz o rozmiarze 50 MB, oznaczało, że do czasu zwolnienia obiektu ClipboardItem w pamięci renderowania strony internetowej trzeba było użyć 50 MB, nawet jeśli aplikacja potrzebowała tylko reprezentacji danych w formacie text/plain. Teraz tylko formaty, które aplikacja odczytuje podczas wywoływania funkcji ClipboardItem.getType(), używają pamięci w procesie renderowania. W przypadku aplikacji, w których wklejanie jest częste, takich jak edytory dokumentów, narzędzia do tworzenia e-maili czy narzędzia do projektowania, znacznie zmniejsza to zużycie pamięci podczas wklejania, zwłaszcza w sesjach z wieloma kartami, w których kilka edytorów może równolegle odczytywać schowek.
Nie trzeba wyrażać zgody. Każda witryna w internecie automatycznie korzysta z tych zalet. Nie musisz migrować kodu ani ograniczać go za pomocą logiki wykrywania funkcji.
Jedna zmiana zachowania, o której warto pamiętać
Późniejsze odczytywanie danych wprowadza niewielką zmianę w zachowaniu: obiekt ClipboardItem nie jest już zamrożonym zrzutem schowka w momencie, gdy wywołanie funkcji navigator.clipboard.read() zostało rozwiązane.
Gdy wywoływana jest funkcja read() i zwraca obiekt ClipboardItem, ten element jest tylko leniwie obsługiwanym uchwytem do danych w schowku systemowym.
Jeśli zawartość schowka zmieni się między wywołaniem funkcji read() a późniejszym wywołaniem funkcji getType(), to wywołanie zostanie odrzucone z powodu błędu InvalidStateError. Dotyczy to nawet formatu, który wcześniej został odczytany z tego samego obiektu 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');
Dzieje się tak, ponieważ zwracanie danych, które nie odzwierciedlają już schowka, byłoby mylące i prowadziłoby do trudnych do debugowania problemów.
W praktyce zmiana jest niewidoczna dla większości kodu, ponieważ aplikacje zwykle wywołują funkcje read() i getType() bezpośrednio w tym samym programie obsługi wklejania. Warto jednak zwrócić uwagę na przypadki, w których kod przechowuje obiekt ClipboardItem w granicach asynchronicznych.
Oto przykład, w którym ta zmiana może stać się problemem: buforowanie obiektów ClipboardItem w obiekcie window, wyświetlanie ich w interfejsie historii schowka lub oczekiwanie na interakcję użytkownika przed wywołaniem funkcji getType(). Aby uniknąć problemów w takim scenariuszu:
- Umieść wywołania funkcji
getType()w blokachtry / catchi traktuj błądInvalidStateErrorjako sygnał, że schowek został zmieniony i kod powinien ponownie odczytać dane. - Jeśli musisz zachować dane ze schowka, skopiuj obiekt
Blobdo własnej struktury zaraz po wywołaniu funkcjigetType(). Nie traktuj obiektuClipboardItemjako długoterminowego miejsca na dane. - Użyj zdarzenia
clipboardChange, aby proaktywnie unieważniać nieaktualne uchwyty.
Standardy i obsługa przeglądarek
Selektywne odczytywanie formatów to zmiana specyfikacji interfejsów Clipboard API wprowadzona przez grupę roboczą Web Editing Working Group i zespół platformy internetowej Microsoft Edge.
Safari też obsługuje to zachowanie, a Firefox zadeklarował a pozytywne stanowisko w sprawie standardów i zamiar dostosowania się do nich.
Cicha, ale znacząca poprawa wydajności i interoperacyjności interfejsu Clipboard API, w przypadku którego Chromium zbliża się do tego samego modelu.