Workercom torna os webworkers agradáveis. O Workercom é uma pequena biblioteca (1,1kb) , que remove a barreira mental de pensar sobre postMessage e esconde o fato de que você está trabalhando com trabalhadores. Questões de comunicação reescritas e aprimoradas da Comlink
Em um nível mais abstrato, é uma implementação de RPC para proxies postMessage e ES6.
$ yarn add workercom
Comlink.proxy (Workercom encontrará funções, transferindo e hidratará)function , class , família Error , família TypedArray e outros Os navegadores sem suporte de proxy ES6 podem usar o poli-poli-polo.
Tamanho : ~ 2,5k, ~ 1,2k gzip'd, ~ 1,1k brotli'd
Em telefones celulares, e especialmente em telefones celulares de ponta, é importante manter o tópico principal o mais ocioso possível para que possa responder às interações do usuário rapidamente e fornecer uma experiência sem o queda. O tópico da interface do usuário deve ser apenas para o trabalho da interface do usuário . Os webworkers são uma API da Web que permite executar o código em um thread separado. Para se comunicar com outro tópico, os webworkers oferecem a API postMessage . Você pode enviar objetos JavaScript como mensagens usando myWorker.postMessage(someObject) , desencadeando um evento message dentro do trabalhador.
O Workercom transforma essa API baseada em mensagens em algo mais favorável ao desenvolvedor, fornecendo uma implementação de RPC: os valores de um thread podem ser usados dentro do outro thread (e vice-versa), assim como os valores locais.
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 ( ) ;trabalhador.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 ( ) ;trabalhador.js
import { expose } from "workercom" ;
async function remoteFunction ( cb ) {
await cb ( "A string from a worker" ) ;
}
expose ( remoteFunction ) ;SharedWorker Ao usar o trabalhador com um SharedWorker você precisa:
port , da instância do SharedWorker , ao ligar para Workercom.wrap .Workercom.expose dentro do retorno de chamada do onconnect do trabalhador compartilhado.Dica profissional: você pode acessar o Devtools para qualquer trabalhador compartilhado que atualmente está executando no Chrome, indo para: 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 ( ) ;trabalhador.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) e Workercom.expose(value, endpoint?) O objetivo do Workercom é disponibilizar valores expostos a um thread no outro. expose expõe value no endpoint , onde endpoint é uma interface semelhante postMessage .
wrap envolve a outra extremidade do canal de mensagens e retorna um proxy. O proxy terá todas as propriedades e funções do valor exposto, mas o acesso e invocações são inerentemente assíncronos. Isso significa que uma função que retorna um número agora retornará uma promessa para um número. Como regra prática: se você estiver usando o proxy, await na frente dele. Exceções serão capturadas e re-arrotadas do outro lado.
Workercom.installTransfer(name, transferables) e Comlink.proxyPor padrão, todos os parâmetros de função, valor de retorno e valor da propriedade do objeto são copiados, no sentido de clonagem estruturada. A clonagem estruturada pode ser considerada uma cópia profunda, mas tem algumas limitações. Veja esta tabela para obter detalhes.
Se você deseja que um valor seja transferido em vez de copiado - desde que o valor seja ou contenha um Transferable - você pode envolver o valor em uma chamada installTransfer() e fornecer uma lista de valores transferíveis:
import { installTransfer } from "workercom" ;
installTransfer < ArrayBuffer , string > ( "arraybuffer" , {
canHandle : ( value ) => value instanceof ArrayBuffer ,
serialize : ( value ) => [ _arrayBufferToBase64 ( value ) , [ ] ] ,
deserialize : ( { raw } ) => _base64ToArrayBuffer ( raw ) ,
} ) ; Removido Comlink.proxy() . Isso vai acontecer automaticamente
// myProxy.onready = Comlink.proxy((data) => {
// /* ... */
// });
// * And now
myProxy . onready = ( data ) => {
/* ... */
}Veja mais transferência padrão
É comum que você queira usar o Workercom para adicionar um ouvinte de eventos, onde a fonte do evento está em outro tópico:
button . addEventListener ( "click" , myProxy . onClick . bind ( myProxy ) ) ; Embora isso não jogue imediatamente, onClick nunca será chamado. Isso ocorre porque Event não é clonável estruturado nem transferível. Como solução alternativa, o Workercom oferece manipuladores de transferência.
Cada parâmetro de função e valor de retorno são fornecidos a todos os manipuladores de transferência registrados. Se um dos manipuladores de eventos sinais de que ele poderá processar o valor retornando true do canHandle() , agora é responsável por serializar o valor a dados claráveis estruturados e por desservar o valor. Um manipulador de transferência foi configurado em ambos os lados do canal de mensagens. Aqui está um exemplo de manipulador de transferência 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 ,
} ) ; Observe que este manipulador de transferência específico não criará um Event real, mas apenas um objeto que possui a propriedade event.target.id e event.target.classList . Muitas vezes, isso é suficiente. Caso contrário, o manipulador de transferência pode ser facilmente aumentado para fornecer todos os dados necessários.
Suporte de conversão padrão para function , class , família Error , família TypedArray
Workercom.releaseProxy Todo proxy criado pelo Workercom possui o método [releaseProxy] . Chamá -lo destacará o proxy e o objeto exposto do canal de mensagens, permitindo que as duas extremidades sejam coletadas de lixo.
const proxy = wrap ( port ) ;
// ... use the proxy ...
proxy [ releaseProxy ] ( ) ;Workercom.createEndpoint Todo proxy criado pelo Workercom possui o método [createEndpoint] . Chamá -lo retornará um novo MessagePort , que foi conectado ao mesmo objeto que o proxy que [createEndpoint] foi chamado.
const port = myProxy [ createEndpoint ] ( ) ;
const newProxy = wrap ( port ) ;Workercom.windowEndpoint(window, context = self, targetOrigin = "*") Windows e Web Workers têm variantes ligeiramente diferentes da postMessage . Se você deseja usar o Workercom para se comunicar com um iframe ou outra janela, precisará embrulhá -lo com windowEndpoint() .
window é a janela com que deve ser comunicada. O context é o EventTarget sobre o qual as mensagens da window podem ser recebidas (geralmente self ). targetOrigin é passado para postMessage e permite filtrar mensagens por origem. Para detalhes, consulte a documentação para Window.postMessage .
Para um exemplo de uso, dê uma olhada nos exemplos de não-trabalhadores na pasta docs .
O Workercom fornece tipos de texto digital. Quando você expose() algo do Tipo T , a chamada wrap() correspondente retornará algo do tipo Workercom.Remote<T> . Embora esse tipo já tenha sido testado em batalha há algum tempo, ele é implementado com melhor efeito. Existem algumas nuances incrivelmente difíceis, se não impossíveis de codificar corretamente no sistema de tipos do TypeScript. Às vezes, pode ser necessário forçar um determinado tipo usando as unknown as <type> .
Workercom trabalha com o módulo worker_threads do Node.
Licença MIT