Selectief formaat lezen: een betere standaard voor de Async Clipboard API

Prashant Singh
Prashant Singh

Gepubliceerd: 3 juli 2026

Als je ooit een tekstverwerker, spreadsheetprogramma of een andere app hebt gebruikt waarbij het plakken van inhoud vanuit het klembord een primaire interactie is, dan weet je wat de gebruiker verwacht: plakken moet direct aanvoelen.

Helaas lezen webapplicaties in veel gevallen meer gegevens van het klembord dan nodig is. Dit kan ervoor zorgen dat het plakken van inhoud trager aanvoelt dan zou moeten, dat er onnodig veel processorkracht wordt verspild en dat er geheugen wordt gebruikt voor gegevens die de applicatie nooit nodig heeft.

Het selectief lezen van formaten pakt dit prestatieprobleem aan door de Async Clipboard API aan te passen, zodat deze beter aansluit op de verwachtingen van de gebruiker en ontwikkelaars biedt wat ze nodig hebben: alleen de formaten lezen die de app daadwerkelijk nodig heeft.

Het probleem: lees alle gegevensformaten vooraf.

Wanneer een gebruiker gegevens kopieert vanuit een app – bijvoorbeeld Excel, Google Docs of Photoshop – schrijft de app meestal verschillende weergaven van dezelfde gegevens naar het klembord: platte tekst, HTML, afbeelding en soms aangepaste opmaak. De webapplicatie die de gegevens leest (wanneer de gebruiker vanuit het klembord plakt) heeft zelden al deze weergaven nodig. Een spreadsheetprogramma wil misschien HTML. Een teksteditor wil misschien een optie 'plakken als platte tekst'. Een code-editor wil misschien alleen de tekst en niets anders.

Tot nu toe haalde navigator.clipboard.read() elke beschikbare weergave van de gegevens uit het systeemklembord, voerde een saneringsbewerking uit (wat tijd kan kosten, vooral bij grote HTML- of afbeeldingsbestanden) en bewaarde de bytes in het geheugen, zelfs voor formaten die de app nooit zou gebruiken. Hoe groter de ongebruikte gegevens, hoe langer de gebruiker moest wachten en hoe meer geheugen het tabblad verbruikte, juist op het moment dat de plakfunctie snel reageert.

De oplossing: Alleen opsommen, vervolgens op aanvraag lezen.

Vanaf versie 149 van Chrome en Edge beschrijven ClipboardItem objecten die worden geretourneerd door de methode navigator.clipboard.read() alleen wat er in het klembord staat , in plaats van direct toegang te geven tot de gegevens. De daadwerkelijke bytes voor een bepaald formaat worden pas van het klembord gelezen wanneer u ClipboardItem.getType(mimeType) aanroept. De API-interface is ongewijzigd. Dezelfde code die u gisteren schreef, werkt vandaag nog steeds en biedt u direct prestatievoordelen:

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

Een ander prestatievoordeel is dat caching automatisch gebeurt. Door getType('text/html') twee keer aan te roepen op hetzelfde ClipboardItem , wordt er slechts één keer van het systeemklembord gelezen en wordt de gecachede Blob bij de tweede aanroep geretourneerd.

De voordelen

Latentie. Het werk dat moest gebeuren wanneer navigator.clipboard.read() werd aangeroepen, zoals het kopiëren van bytes tussen processen, het opschonen van HTML of het decoderen van afbeeldingen, gebeurt nu alleen nog voor de formaten die uw app daadwerkelijk nodig heeft. Apps die slechts één formaat lezen, profiteren het meest van de besparing. Hoe groter de formaten die u overslaat, hoe groter de winst. HTML profiteert het meest, omdat het opschonen van HTML kostbaar is.

Geheugen. Voorheen betekende het aanroepen van navigator.clipboard.read() wanneer het klembord een afbeelding van 50 MB bevatte, dat er 50 MB geheugen van de renderer van de webpagina werd gebruikt totdat het ClipboardItem werd vrijgegeven, zelfs als de app alleen de text/plain -weergave van de gegevens nodig had. Nu gebruiken alleen de formaten die uw app leest bij het aanroepen ClipboardItem.getType() geheugen in het rendererproces. Voor apps waar plakken vaak voorkomt, zoals documenteditors, e-mailprogramma's of ontwerptools, vermindert dit het geheugengebruik tijdens het plakken aanzienlijk, vooral in sessies met meerdere tabbladen waarbij verschillende editors mogelijk parallel het klembord lezen.

Geen opt-in nodig. Elke website profiteert automatisch van deze voordelen. U hoeft geen code te migreren of code te beveiligen achter de logica voor functiedetectie.

Een gedragsverandering waar je rekening mee moet houden.

Het later uitlezen van de gegevens introduceert een kleine gedragsverandering: een ClipboardItem object is niet langer een bevroren momentopname van het klembord op het moment dat de aanroep van navigator.clipboard.read() werd voltooid.

Wanneer read() wordt aangeroepen en een ClipboardItem retourneert, is dit item slechts een 'lazy handle' naar de gegevens in het systeemklembord. Als de inhoud van het klembord verandert tussen de aanroep van read() en een latere aanroep van getType() , wordt die aanroep geweigerd met een InvalidStateError . Dit geldt zelfs voor een formaat dat u eerder succesvol hebt gelezen op hetzelfde 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');

Dit gebeurt omdat het retourneren van gegevens die niet langer overeenkomen met de inhoud van het klembord verwarrend zou zijn en anders tot moeilijk op te sporen problemen zou leiden.

In de praktijk is de wijziging voor de meeste code onzichtbaar, omdat apps doorgaans read() en getType() direct na elkaar aanroepen binnen dezelfde plakhandler. Het is echter raadzaam om alert te zijn op gevallen waarin code een ClipboardItem vasthoudt over asynchrone grenzen heen.

Hier is een voorbeeld waarbij deze wijziging een probleem kan worden: het cachen ClipboardItem objecten in window , het weergeven ervan in een gebruikersinterface voor de klembordgeschiedenis, of het wachten op gebruikersinteractie voordat getType() wordt aangeroepen. Om problemen met een dergelijk scenario te voorkomen:

  • Plaats getType() aanroepen in try / catch blokken en beschouw InvalidStateError als een signaal dat het klembord is gewijzigd en dat de code opnieuw moet lezen.
  • Als u klembordgegevens wilt bewaren, kopieert u de Blob naar uw eigen structuur zodra u deze getType() . Beschouw het ClipboardItem niet als permanente opslag.
  • Gebruik de clipboardChange gebeurtenis om proactief verouderde handles ongeldig te maken.

Standaarden en browserondersteuning

Het selectief lezen van formaten is een wijziging in de specificaties van de Clipboard API's, geïnitieerd door de Web Editing Working Group en het Microsoft Edge-webplatformteam.

Safari ondersteunt dit gedrag ook, en Firefox heeft een positief standpunt ten aanzien van de standaarden ingenomen en de intentie uitgesproken om zich hieraan aan te passen.

Een stille, maar betekenisvolle verbetering van de prestaties en interoperabiliteit van de Clipboard API, waarbij Chromium nu naar hetzelfde model convergeert.