Workercom macht Webworker angenehm. WorkerCom ist eine winzige Bibliothek (1,1 KB) , die die mentale Hindernis des Nachdenkens über postMessage beseitigt und die Tatsache versteckt, dass Sie mit Arbeitnehmern arbeiten. Umgeschriebene und verbesserte Kommunikationsprobleme von Comlink umgerichtet und verbessert
Auf einer abstrakteren Ebene handelt es sich um eine RPC -Implementierung für postMessage und ES6 -Proxies.
$ yarn add workercom
Comlink.proxy (Workercom findet Funktionen, übertragen und hydratisiert sie)function , class , Error , TypedArray -Familie und andere Browser ohne ES6-Proxy-Unterstützung können die Proxy-Polyfill verwenden.
Größe : ~ 2,5K, ~ 1,2K gzip'd, ~ 1,1K brotli'd
Bei Mobiltelefonen und insbesondere bei Mobiltelefonen mit niedrigem Ende ist es wichtig, den Hauptfaden so untätig wie möglich zu halten, damit er schnell auf Benutzerinteraktionen reagieren und ein verstecktes Erlebnis bieten kann. Der UI -Thread sollte nur für UI -Arbeiten sein . Webworker sind eine Web -API, mit der Sie Code in einem separaten Thread ausführen können. Um mit einem anderen Thread zu kommunizieren, bieten Webworker die postMessage -API an. Sie können JavaScript -Objekte als Nachrichten mit myWorker.postMessage(someObject) senden und ein message innerhalb des Arbeiters auslösen.
WorkerCom verwandelt diese mit einem gemeldeten basierende API in etwas Entwicklerfreundlicher, indem eine RPC-Implementierung bereitgestellt wird: Werte aus einem Thread können in dem anderen Thread (und umgekehrt) genau wie die lokalen Werte verwendet werden.
main.js
import { wrap } from "workercom" ;
import Worker from "worker-loader!./worker.js" ;
async function init ( ) {
const worker = new Worker ( ) ;
// WebWorkers use `postMessage` and therefore work with Workercom.
const obj = wrap ( worker ) ;
alert ( `Counter: ${ await obj . counter } ` ) ;
await obj . inc ( ) ;
alert ( `Counter: ${ await obj . counter } ` ) ;
}
init ( ) ;Worker.js
import { expose } from "workercom" ;
const obj = {
counter : 0 ,
inc ( ) {
this . counter ++ ;
} ,
} ;
expose ( obj ) ;main.js
import { wrap } from "workercom" ;
import Worker from "worker-loader!./worker.js" ;
async function init ( ) {
const remoteFunction = wrap ( new Worker ( ) ) ;
await remoteFunction ( callback ( value ) {
alert ( `Result: ${ value } ` ) ;
} ) ;
}
init ( ) ;Worker.js
import { expose } from "workercom" ;
async function remoteFunction ( cb ) {
await cb ( "A string from a worker" ) ;
}
expose ( remoteFunction ) ;SharedWorker Wenn Sie WorkerCom mit einem SharedWorker verwenden, müssen Sie:
port der SharedWorker -Instanz, wenn Sie Workercom.wrap aufrufen.Workercom.expose innerhalb des onconnect -Rückrufs des Shared Worker aus.Pro -Tipp: Sie können auf Devtools für jeden gemeinsamen Mitarbeiter zugreifen
main.js
import { wrap } from "workercom" ;
import SharedWorker from "worker-loader?worker=SharedWorker!./worker.js" ;
async function init ( ) {
const worker = new SharedWorker ( ) ;
/**
* SharedWorkers communicate via the `postMessage` function in their `port` property.
* Therefore you must use the SharedWorker's `port` property when calling `Workercom.wrap`.
*/
const obj = wrap ( worker . port ) ;
alert ( `Counter: ${ await obj . counter } ` ) ;
await obj . inc ( ) ;
alert ( `Counter: ${ await obj . counter } ` ) ;
}
init ( ) ;Worker.js
import { expose } from "workercom" ;
const obj = {
counter : 0 ,
inc ( ) {
this . counter ++ ;
} ,
} ;
/**
* When a connection is made into this shared worker, expose `obj`
* via the connection `port`.
*/
onconnect = function ( event ) {
const port = event . ports [ 0 ] ;
expose ( obj , port ) ;
} ;
// Single line alternative:
// onconnect = (e) => expose(obj, e.ports[0]); Workercom.wrap(endpoint) und Workercom.expose(value, endpoint?) Das Ziel von Workercom ist es, exponierte Werte von einem Thread in den anderen verfügbar zu machen. expose value auf endpoint , wobei endpoint eine postMessage Schnittstelle ist.
wrap das andere Ende des Nachrichtenkanals ein und gibt einen Proxy zurück. Der Proxy verfügt über alle Eigenschaften und Funktionen des exponierten Werts, aber der Zugriff und die Aufrufe sind von Natur aus asynchron. Dies bedeutet, dass eine Funktion, die eine Nummer zurückgibt, nun ein Versprechen für eine Nummer zurückgibt. Als Faustregel: Wenn Sie den Proxy verwenden, await Sie darauf. Ausnahmen werden auf der anderen Seite gefangen und wiedergeworfen.
Workercom.installTransfer(name, transferables) & Comlink.proxyStandardmäßig wird jeder Funktionsparameter, jeder Rückgabewert und jeder Objekteigenschaftswert im Sinne des strukturierten Klonen kopiert. Strukturiertes Klonen kann als tiefes Kopieren angesehen werden, hat jedoch einige Einschränkungen. Weitere Informationen finden Sie in dieser Tabelle.
Wenn Sie möchten, dass ein Wert übertragen und nicht kopiert wird - vorausgesetzt, der Wert ist oder enthält ein Transferable -, können Sie den Wert in einen installTransfer() -Anruf einwickeln und eine Liste übertragbarer Werte angeben:
import { installTransfer } from "workercom" ;
installTransfer < ArrayBuffer , string > ( "arraybuffer" , {
canHandle : ( value ) => value instanceof ArrayBuffer ,
serialize : ( value ) => [ _arrayBufferToBase64 ( value ) , [ ] ] ,
deserialize : ( { raw } ) => _base64ToArrayBuffer ( raw ) ,
} ) ; Comlink.proxy() entfernt. Dies wird automatisch passieren
// myProxy.onready = Comlink.proxy((data) => {
// /* ... */
// });
// * And now
myProxy . onready = ( data ) => {
/* ... */
}Weitere Standardübertragungen finden Sie in der Standardübertragung
Es ist üblich, dass Sie Workercom verwenden möchten, um einen Event -Listener hinzuzufügen, bei dem sich die Ereignisquelle in einem anderen Thread befindet:
button . addEventListener ( "click" , myProxy . onClick . bind ( myProxy ) ) ; Während dies nicht sofort werfen wird, wird onClick niemals angerufen. Dies liegt daran, dass Event weder strukturiertes klonbar noch übertragbar ist. Als Problemumgehung bietet Workercom Transfer -Handler an.
Jeder Funktionsparameter und jeder Rückgabewert wird an alle registrierten Übertragungshandler angegeben. Wenn einer der Ereignisbehandlungen signalisiert, dass er den Wert verarbeiten kann, indem er true von canHandle() zurückgegeben wird, ist er nun für die Serialisierung des Wertes auf strukturierte klonbare Daten und für die Deserialisierung des Wertes verantwortlich. Auf beiden Seiten des Nachrichtenkanals wurde ein Transfer -Handler eingerichtet. Hier ist ein Beispiel -Transfer -Handler für Ereignisse:
installTransfer < Event , {
target : {
id : string ;
classList : string [ ]
}
} > ( "EVENT" , {
canHandle : ( obj ) => obj instanceof Event ,
serialize : ( ev ) => {
return [
{
target : {
id : ev . target . id ,
classList : [ ... ev . target . classList ] ,
} ,
} ,
[ ] ,
] ;
} ,
deserialize : ( obj ) => obj ,
} ) ; Beachten Sie, dass dieser bestimmte Transfer -Handler kein tatsächliches Event erstellt, sondern nur ein Objekt mit der event.target.id und event.target.classList -Eigenschaft. Oft reicht das aus. Wenn nicht, kann der Transfer -Handler leicht erweitert werden, um alle erforderlichen Daten bereitzustellen.
Standardkonvertier -Unterstützung für function , class , Error , TypedArray -Familie
Workercom.releaseProxy Jeder von WorkerCom erstellte Proxy hat die Methode [releaseProxy] . Wenn Sie ihn aufrufen, wird der Proxy und das exponierte Objekt vom Nachrichtenkanal abgenommen, sodass beide Enden Müll gesammelt werden können.
const proxy = wrap ( port ) ;
// ... use the proxy ...
proxy [ releaseProxy ] ( ) ;Workercom.createEndpoint Jeder von WorkerCom erstellte Proxy hat die Methode [createEndpoint] . Wenn Sie es aufrufen, wird ein neues MessagePort zurückgegeben, das demselben Objekt wie der Proxy angeschlossen wurde, den [createEndpoint] aufgerufen wurde.
const port = myProxy [ createEndpoint ] ( ) ;
const newProxy = wrap ( port ) ;Workercom.windowEndpoint(window, context = self, targetOrigin = "*") Windows und Webarbeiter haben eine etwas andere Varianten der postMessage . Wenn Sie WorkerCom verwenden möchten, um mit einem Iframe oder einem anderen Fenster zu kommunizieren, müssen Sie es mit windowEndpoint() einwickeln.
window ist das Fenster, mit dem sie kommunizieren sollten. Der context ist das EventTarget , auf dem Nachrichten aus dem window empfangen werden können (oft self ). targetOrigin wird an postMessage übergeben und ermöglicht es, Nachrichten nach Herkunft zu filtern. Weitere Informationen finden Sie in der Dokumentation für Window.postMessage .
Für ein Nutzungsbeispiel schauen Sie sich die Beispiele für Nichtarbeiter im docs Ordner an.
WorkerCom bietet TypeScript -Typen an. Wenn Sie () etwas vom Typ T expose() , gibt der entsprechende wrap() -Anruf etwas vom Typ Workercom.Remote<T> zurück. Während dieser Typ in jetziger Kampf in jetziger Kampf geprüft wurde, wird er auf Best-Effort-Basis implementiert. Es gibt einige Nuancen, die unglaublich schwierig sind, wenn nicht unmöglich, im Typ -System von TypeScript korrekt zu codieren. Es kann manchmal notwendig sein, einen bestimmten Typ mit as unknown as <type> zu erzwingen.
Workercom arbeitet mit dem worker_threads -Modul von Node.
Lizenz MIT