WorkerCom rend les travailleurs Web agréables. Workercom est une petite bibliothèque (1,1 kb) , qui supprime la barrière mentale de penser à postMessage et cache le fait que vous travaillez avec les travailleurs. Problèmes de communication réécrits et améliorés de ComLink
À un niveau plus abstrait, il s'agit d'une implémentation RPC pour les proxys postMessage et ES6.
$ yarn add workercom
Comlink.proxy inutile (WorkerCom trouvera des fonctions, les transférer et les hydrater)function , class , la famille Error , la famille TypedArray et d'autres Les navigateurs sans support proxy ES6 peuvent utiliser le proxy-polyfill.
Taille : ~ 2,5k, ~ 1,2k gzip'd, ~ 1,1k brotli'd
Sur les téléphones mobiles, et en particulier sur les téléphones mobiles bas de gamme, il est important de garder le fil principal aussi inactif que possible afin qu'il puisse répondre rapidement aux interactions des utilisateurs et offrir une expérience sans Jank. Le fil d'interface utilisateur ne devrait être que pour l'interface utilisateur . Les travailleurs Web sont une API Web qui vous permet d'exécuter du code dans un thread séparé. Pour communiquer avec un autre fil, les travailleurs Web offrent l'API postMessage . Vous pouvez envoyer des objets JavaScript sous forme de messages à l'aide myWorker.postMessage(someObject) , déclenchant un événement message dans le travailleur.
WorkerCom transforme cette API basée sur un message en un quelque chose de plus adapté aux développeurs en fournissant une implémentation RPC: les valeurs d'un thread peuvent être utilisées dans l'autre thread (et vice versa) tout comme les valeurs 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 ( ) ;wearch.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 ( ) ;wearch.js
import { expose } from "workercom" ;
async function remoteFunction ( cb ) {
await cb ( "A string from a worker" ) ;
}
expose ( remoteFunction ) ;SharedWorker Lorsque vous utilisez WorkerCom avec un SharedWorker vous devez:
port , de l'instance SharedWorker , lors de l'appel Workercom.wrap .Workercom.expose dans le rappel onconnect du travailleur partagé.Conseil de pro: vous pouvez accéder à Devtools pour tout travailleur partagé en cours d'exécution en Chrome en allant à: Chrome: // Inspecter / # travailleurs
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 ( ) ;wearch.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) et Workercom.expose(value, endpoint?) L'objectif de WorkerCom est de rendre les valeurs exposées à partir d'un fil à disposition dans l'autre. expose expose value sur endpoint , où endpoint est une interface de type postMessage .
wrap enroule l' autre extrémité du canal de message et renvoie un proxy. Le proxy aura toutes les propriétés et fonctions de la valeur exposée, mais l'accès et les invocations sont intrinsèquement asynchrones. Cela signifie qu'une fonction qui renvoie un nombre renverra désormais une promesse pour un nombre. En règle générale: si vous utilisez le proxy, mettez await en attente. Des exceptions seront capturées et remontées de l'autre côté.
Workercom.installTransfer(name, transferables) et Comlink.proxyPar défaut, chaque paramètre de fonction, valeur de retour et valeur de propriété de l'objet est copié, dans le sens du clonage structuré. Le clonage structuré peut être considéré comme une copie profonde, mais a certaines limites. Voir ce tableau pour plus de détails.
Si vous souhaitez que une valeur soit transférée plutôt que copiée - à condition que la valeur soit ou contient une Transferable - vous pouvez envelopper la valeur dans un appel installTransfer() et fournir une liste de valeurs transférables:
import { installTransfer } from "workercom" ;
installTransfer < ArrayBuffer , string > ( "arraybuffer" , {
canHandle : ( value ) => value instanceof ArrayBuffer ,
serialize : ( value ) => [ _arrayBufferToBase64 ( value ) , [ ] ] ,
deserialize : ( { raw } ) => _base64ToArrayBuffer ( raw ) ,
} ) ; Supprimé Comlink.proxy() . Cela se produira automatiquement
// myProxy.onready = Comlink.proxy((data) => {
// /* ... */
// });
// * And now
myProxy . onready = ( data ) => {
/* ... */
}Voir plus de transfert par défaut
Il est courant que vous souhaitiez utiliser WorkerCom pour ajouter un écouteur d'événements, où la source d'événement se trouve sur un autre fil:
button . addEventListener ( "click" , myProxy . onClick . bind ( myProxy ) ) ; Bien que cela ne lance pas immédiatement, onClick ne sera jamais appelé. En effet, Event n'est ni structuré clonable ni transférable. En tant que solution de contournement, WorkerCom propose des gestionnaires de transfert.
Chaque paramètre de fonction et la valeur de retour est donné à tous les gestionnaires de transfert enregistrés. Si l'un des gestionnaires d'événements signale qu'il peut traiter la valeur en renvoyant true de canHandle() , il est désormais responsable de la sérialisation de la valeur aux données clonables structurées et de désérialisation de la valeur. Un gestionnaire de transfert est configuré des deux côtés du canal de message. Voici un exemple de gestionnaire de transfert pour les événements:
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 ,
} ) ; Notez que ce gestionnaire de transfert particulier ne créera pas un Event réel, mais juste un objet qui a la propriété event.target.id et event.target.classList . Souvent, cela suffit. Sinon, le gestionnaire de transfert peut être facilement augmenté pour fournir toutes les données nécessaires.
Prise en charge de la conversion par défaut pour function , class , la famille Error , la famille TypedArray
Workercom.releaseProxy Chaque proxy créé par WorkerCom a la méthode [releaseProxy] . L'appeler détachera le proxy et l'objet exposé du canal de message, permettant aux deux extrémités d'être collectées.
const proxy = wrap ( port ) ;
// ... use the proxy ...
proxy [ releaseProxy ] ( ) ;Workercom.createEndpoint Chaque proxy créé par WorkerCom a la méthode [createEndpoint] . L'appeler renverra un nouveau MessagePort , qui a été connecté au même objet que le proxy que [createEndpoint] a été appelé.
const port = myProxy [ createEndpoint ] ( ) ;
const newProxy = wrap ( port ) ;Workercom.windowEndpoint(window, context = self, targetOrigin = "*") Les Windows et les travailleurs du Web ont une variante légèrement différente de postMessage . Si vous souhaitez utiliser WorkerCom pour communiquer avec un iframe ou une autre fenêtre, vous devez l'envelopper avec windowEndpoint() .
window est la fenêtre avec laquelle il faut communiquer. context est l' EventTarget sur lequel les messages de la window peuvent être reçus (souvent self ). targetOrigin est passé par postMessage et permet de filtrer les messages par origine. Pour plus de détails, consultez la documentation de Window.postMessage .
Pour un exemple d'utilisation, jetez un œil aux exemples de non-travailleurs dans le dossier docs .
WorkerCom fournit des types de dactylographies. Lorsque vous expose() quelque chose de type T , l'appel wrap() correspondant renverra quelque chose de type Workercom.Remote<T> . Bien que ce type ait été testé au combat depuis un certain temps maintenant, il est mis en œuvre sur une base le plus efficace. Il y a des nuances qui sont incroyablement difficiles, voire impossibles, à coder correctement dans le système de type TypeScript. Il peut parfois être nécessaire de forcer un certain type en utilisant as unknown as <type> .
WorkerCom fonctionne avec le module worker_threads de Node.
Licence MIT