Chrome 13 introduceerde het verzenden van ArrayBuffer
-bestanden naar/van een webwerker met behulp van een algoritme dat gestructureerd klonen wordt genoemd. Hierdoor kon de postMessage()
API berichten accepteren die niet alleen uit tekenreeksen bestonden, maar uit complexe typen zoals File
, Blob
, ArrayBuffer
en JSON-objecten. Gestructureerd klonen wordt ook ondersteund in latere versies van Firefox.
Sneller is beter
Gestructureerd klonen is geweldig, maar het is nog steeds een kopieeroperatie. De overhead van het doorgeven van een ArrayBuffer
van 32 MB aan een Worker kan honderden milliseconden bedragen. Nieuwe versies van browsers bevatten een enorme prestatieverbetering voor het doorgeven van berichten, genaamd Transferable Objects .
Bij overdraagbare objecten worden gegevens van de ene context naar de andere overgedragen. Het is zero-copy, wat de prestaties bij het verzenden van gegevens naar een werknemer enorm verbetert. Beschouw het als een pass-by-referentie als je uit de C/C++-wereld komt. In tegenstelling tot pass-by-referentie is de 'versie' uit de aanroepende context echter niet langer beschikbaar zodra deze naar de nieuwe context is overgebracht. Wanneer u bijvoorbeeld een ArrayBuffer
van uw hoofdapp naar Worker overzet, wordt de oorspronkelijke ArrayBuffer
gewist en niet langer bruikbaar. De inhoud ervan wordt (letterlijk) overgebracht naar de Worker-context.
Om met overdraagbare objecten te spelen, is er een nieuwe versie van postMessage()
die overdraagbare objecten ondersteunt:
worker.postMessage(arrayBuffer, [transferableList]);
window.postMessage(arrayBuffer, targetOrigin, [transferableList]);
Voor de werksituatie is het eerste argument het ArrayBuffer
bericht. Het tweede argument is een lijst met items die moeten worden overgedragen. In dit voorbeeld geeft u de arrayBuffer
op in de overdraagbare lijst.
Benchmark-demo
Om de prestatiewinst van overdraagbare bestanden te zien, heb ik een demo samengesteld.
De demo stuurt een ArrayBuffer
van 32 MB naar een werker en terug met behulp van postMessage()
. Als uw browser geen overdraagbare bestanden ondersteunt, valt het voorbeeld terug op gestructureerd klonen. Gemiddeld vijf keer uitgevoerd in verschillende browsers, dit is wat ik heb:
Op een MacBook Pro/10.6.8/2.53 GHz/Intel Core 2 Duo was FF de snelste met behulp van gestructureerd klonen. Gemiddeld duurde het 302 ms om de ArrayBuffer
van 32 MB naar een medewerker te sturen en deze terug te plaatsen in de hoofdthread (RRT - Round Trip Time). Als je dat vergelijkt met overdraagbare bestanden, duurde dezelfde test 6,6 ms. Dat is een enorme prestatieboost!
Met dit soort snelheden kunnen enorme WebGL-texturen/meshes naadloos worden doorgegeven tussen een Worker en de hoofdapp.
Functiedetectie
Het detecteren van functies is hierbij een beetje lastig. Mijn aanbeveling is om een kleine ArrayBuffer
naar uw werker te sturen. Als de buffer wordt overgedragen en niet wordt gekopieerd, gaat de .byteLength
naar 0:
var ab = new ArrayBuffer(1);
worker.postMessage(ab, [ab]);
if (ab.byteLength) {
alert('Transferables are not supported in your browser!');
} else {
// Transferables are supported.
}
Ondersteuning: momenteel Chrome 17+, Firefox, Opera, Safari en IE10+
Bijgewerkt (13-12-2011): Codefragment om de handtekening webkitPostMessage()
weer te geven is verschillend voor venster en werker. Bijgewerkt (03-11-2016): Voorvoegsels van leveranciers verwijderd en codefragmenten bijgewerkt