Chrome 13 ha introdotto l'invio di ArrayBuffer
a/da un web worker utilizzando un algoritmo chiamato clonazione strutturata. In questo modo, l'API postMessage()
ha potuto accettare messaggi non solo di stringhe, ma anche di tipi complessi come File
, Blob
, ArrayBuffer
e oggetti JSON. La clonazione strutturata è supportata anche nelle versioni successive di Firefox.
Più veloce è meglio
La clonazione strutturata è ottima, ma si tratta comunque di un'operazione di copia. L'overhead di passaggio di un ArrayBuffer
di 32 MB a un worker può essere di centinaia di millisecondi.
Le nuove versioni dei browser contengono un enorme miglioramento delle prestazioni per la trasmissione dei messaggi, chiamato oggetti trasferibili.
Con gli oggetti trasferibili, i dati vengono trasferiti da un contesto all'altro. È una copia zero, il che migliora notevolmente le prestazioni dell'invio di dati a un worker. Pensalo come a un passaggio per riferimento se ti occupi di C/C++. Tuttavia, a differenza del passaggio per riferimento, la "versione" del contesto di chiamata non è più disponibile una volta trasferita al nuovo contesto. Ad esempio, quando trasferisci un ArrayBuffer
dall'app principale a Worker, l'ArrayBuffer
originale viene cancellato e non è più utilizzabile. I relativi contenuti vengono (letteralmente) trasferiti al contesto del worker.
Per giocare con gli oggetti trasferibili, è disponibile una nuova versione di postMessage()
che supporta gli oggetti trasferibili:
worker.postMessage(arrayBuffer, [transferableList]);
window.postMessage(arrayBuffer, targetOrigin, [transferableList]);
Per la richiesta dell'operatore, il primo argomento è il messaggio ArrayBuffer
. Il secondo argomento è un elenco di elementi da trasferire. In questo esempio, devi specificare arrayBuffer
nell'elenco trasferibile.
Demo di benchmark
Per vedere i miglioramenti del rendimento dei trasferibili, ho creato una demo.
La demo invia un ArrayBuffer
di 32 MB a un worker e viceversa utilizzando postMessage()
. Se il tuo browser non supporta gli elementi trasferibili, il sample torna alla clonazione strutturata. Ecco cosa ho ottenuto con una media di 5 esecuzioni in browser diversi:
Su un MacBook Pro/10.6.8/2,53 GHz/Intel Core 2 Duo, FF è stato il più veloce con la clonazione strutturata. In media, sono stati necessari 302 ms per inviare ArrayBuffer
da 32 MB a un worker e per postarlo di nuovo nel thread principale (RRT, tempo di round trip). Se confrontato con i trasferibili, lo stesso test ha richiesto 6,6 ms. Si tratta di un enorme miglioramento delle prestazioni.
Queste velocità consentono di trasferire senza problemi texture/mesh WebGL di grandi dimensioni tra un worker e l'app principale.
Rilevamento di funzionalità
Il rilevamento delle funzionalità è un po' complicato in questo caso. Ti consiglio di inviare un piccolo ArrayBuffer
al tuo worker. Se il buffer viene trasferito e non copiato, il relativo .byteLength
diventa 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.
}
Supporto: attualmente Chrome 17 e versioni successive, Firefox, Opera, Safari e IE 10 e versioni successive
Aggiornato (13/12/2011): lo snippet di codice per mostrare la firma webkitPostMessage()
è diversa per la finestra e il worker.
Aggiornamento (03/11/2016): sono stati rimossi i prefissi dei fornitori e aggiornati gli snippet di codice