Workercom hace que los trabajadores web sean agradables. Workercom es una pequeña biblioteca (1.1kb) , que elimina la barrera mental de pensar en postMessage y oculta el hecho de que está trabajando con los trabajadores. Problemas de comunicación reescritos y mejorados de Comlink
En un nivel más abstracto, es una implementación de RPC para los proxies postMessage y ES6.
$ yarn add workercom
Comlink.proxy .function , class , familia Error , familia TypedArray y otros Los navegadores sin soporte de proxy ES6 pueden usar el proxy-polyfill.
Tamaño : ~ 2.5k, ~ 1.2k gzip'd, ~ 1.1k brotli'd
En los teléfonos móviles, y especialmente en los teléfonos móviles de gama baja, es importante mantener el hilo principal lo más inactivo posible para que pueda responder a las interacciones del usuario rápidamente y proporcionar una experiencia sin Jank. El hilo de la interfaz de usuario debe ser solo para el trabajo de interfaz de usuario . Los trabajadores web son una API web que le permite ejecutar código en un hilo separado. Para comunicarse con otro hilo, los trabajadores web ofrecen la API postMessage . Puede enviar objetos JavaScript como mensajes usando myWorker.postMessage(someObject) , activando un evento message dentro del trabajador.
Workercom convierte esta API basada en mensajes en algo más amigable para el desarrollador al proporcionar una implementación de RPC: los valores de un hilo se pueden usar dentro del otro hilo (y viceversa) al igual que los valores locales.
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 ( ) ;trabajador.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 ( ) ;trabajador.js
import { expose } from "workercom" ;
async function remoteFunction ( cb ) {
await cb ( "A string from a worker" ) ;
}
expose ( remoteFunction ) ;SharedWorker Al usar Workercom con un SharedWorker debe:
port , de la instancia SharedWorker , cuando llame Workercom.wrap .Workercom.expose dentro de la devolución de llamada onconnect del trabajador compartido.Consejo profesional: puede acceder a DevTools para cualquier trabajador compartido que se ejecute actualmente en Chrome yendo a: Chrome: // Inspect/#Workers
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 ( ) ;trabajador.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) y Workercom.expose(value, endpoint?) El objetivo de Workercom es hacer que los valores expuestos de un hilo estén disponibles en el otro. expose value de exponidos en endpoint , donde endpoint es una interfaz similar a postMessage .
wrap el otro extremo del canal de mensajes y devuelve un proxy. El proxy tendrá todas las propiedades y funciones del valor expuesto, pero el acceso e invocaciones son inherentemente asíncronas. Esto significa que una función que devuelve un número ahora devolverá una promesa para un número. Como regla general: si está utilizando el proxy, póngase await frente a él. Las excepciones serán atrapadas y repladentes en el otro lado.
Workercom.installTransfer(name, transferables) y Comlink.proxyPor defecto, se copia cada parámetro de función, valor de retorno y valor de propiedad del objeto, en el sentido de clonación estructurada. La clonación estructurada puede considerarse como una copia profunda, pero tiene algunas limitaciones. Vea esta tabla para más detalles.
Si desea que se transfiera un valor en lugar de copiarse, siempre que el valor sea o contenga un Transferable , puede envolver el valor en una llamada installTransfer() y proporcionar una lista de valores transferibles:
import { installTransfer } from "workercom" ;
installTransfer < ArrayBuffer , string > ( "arraybuffer" , {
canHandle : ( value ) => value instanceof ArrayBuffer ,
serialize : ( value ) => [ _arrayBufferToBase64 ( value ) , [ ] ] ,
deserialize : ( { raw } ) => _base64ToArrayBuffer ( raw ) ,
} ) ; Eliminado Comlink.proxy() . Esto sucederá automáticamente
// myProxy.onready = Comlink.proxy((data) => {
// /* ... */
// });
// * And now
myProxy . onready = ( data ) => {
/* ... */
}Ver más transferencia predeterminada
Es común que desee usar Workercom para agregar un oyente de eventos, donde la fuente del evento está en otro hilo:
button . addEventListener ( "click" , myProxy . onClick . bind ( myProxy ) ) ; Si bien esto no lanzará de inmediato, onClick nunca se llamará. Esto se debe a que Event no es estructurado clonable ni transferible. Como solución, Workercom ofrece manejadores de transferencia.
Cada parámetro de función y valor de retorno se proporciona a todos los controladores de transferencia registrados. Si uno de los controladores de eventos señala que puede procesar el valor devolviendo true de canHandle() , ahora es responsable de serializar el valor a los datos clonables estructurados y de la deserialización del valor. Se ha configurado un controlador de transferencia en ambos lados del canal de mensajes. Aquí hay un manejador de transferencia de ejemplo para eventos:
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 ,
} ) ; Tenga en cuenta que este controlador de transferencia en particular no creará un Event real, sino solo un objeto que tiene la propiedad event.target.id y event.target.classList . A menudo, esto es suficiente. Si no, el controlador de transferencia se puede aumentar fácilmente para proporcionar todos los datos necesarios.
Soporte de conversión predeterminado para function , class , familia Error , familia TypedArray
Workercom.releaseProxy Cada proxy creado por Workercom tiene el método [releaseProxy] . Llamarlo se separará el proxy y el objeto expuesto del canal de mensajes, lo que permite que ambos extremos se recolecten basura.
const proxy = wrap ( port ) ;
// ... use the proxy ...
proxy [ releaseProxy ] ( ) ;Workercom.createEndpoint Cada proxy creado por Workercom tiene el método [createEndpoint] . Llamarlo devolverá un nuevo MessagePort , que se ha conectado al mismo objeto que el proxy al que se ha llamado [createEndpoint] .
const port = myProxy [ createEndpoint ] ( ) ;
const newProxy = wrap ( port ) ;Workercom.windowEndpoint(window, context = self, targetOrigin = "*") Windows y los trabajadores web tienen variantes ligeramente diferentes de postMessage . Si desea usar WorkerCom para comunicarse con un iframe u otra ventana, debe envolverlo con windowEndpoint() .
window es la ventana con la que debe comunicarse. context es el EventTarget en el que se pueden recibir mensajes desde la window (a menudo self ). targetOrigin se pasa al postMessage y permite filtrar mensajes por origen. Para más detalles, consulte la documentación para Window.postMessage .
Para un ejemplo de uso, eche un vistazo a los ejemplos de no trabajadores en la carpeta docs .
Workercom proporciona tipos de mecanografiado. Cuando expose() algo de tipo T , la llamada wrap() correspondiente devolverá algo de Type Workercom.Remote<T> . Si bien este tipo se ha probado la batalla durante algún tiempo, se implementa el mejor esfuerzo. Hay algunos matices que son increíblemente difíciles, si no imposibles, de codificar correctamente en el sistema de tipos de TypeScript. A veces puede ser necesario forzar un tipo determinado usando as unknown as <type> .
Workercom trabaja con el módulo worker_threads de Node.
MIT de licencia