WorkerCom使网络工作人员愉快。 WorkerCom是一个很小的图书馆(1.1KB) ,它消除了postMessage的心理障碍,并隐藏了您正在与工人合作的事实。重写并改善了ComLink的沟通问题
在更抽象的层面上,它是用于postMessage和ES6代理的RPC实现。
$ yarn add workercom
Comlink.proxy函数(WorkerCom将找到功能,转移和补充它们)function , class , Error家族, TypedArray家庭和其他没有ES6代理支持的浏览器可以使用代理polyfill。
尺寸:〜2.5k,〜1.2k gzip'd,〜1.1k brotli'd
在手机,尤其是在低端手机上,保持主线程尽可能闲置很重要,以便可以快速响应用户互动并提供无垃圾的体验。 UI线程应仅用于UI工作。 Webworkers是一个Web API,可让您在单独的线程中运行代码。为了与另一个线程进行通信,网络工作人员提供了postMessage API。您可以使用myWorker.postMessage(someObject)将JavaScript对象作为消息发送,从而在工作人员内触发message事件。
WorkerCom通过提供RPC实现来将此基于消息的API变成更友好的事物:来自一个线程的值可以像本地值一样在另一个线程中使用(并且反之亦然)。
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 ( ) ;工人
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 ( ) ;工人
import { expose } from "workercom" ;
async function remoteFunction ( cb ) {
await cb ( "A string from a worker" ) ;
}
expose ( remoteFunction ) ;SharedWorker与SharedWorker一起使用WorkerCom时,您必须:
Workercom.wrap时,请使用SharedWorker实例的port属性。onconnect回调中拨打Workercom.expose 。专家提示:您可以访问当前在Chrome中运行的任何共享工人的DevTools,请访问: chrome:// ixpress/#工人
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 ( ) ;工人
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)和Workercom.expose(value, endpoint?) WorkerCom的目标是从一个可用的一个线程中制作出暴露的值。 expose在endpoint上公开value ,其中endpoint是postMessage类似的接口。
wrap包裹消息频道的另一端,并返回代理。代理将具有暴露值的所有属性和功能,但是访问和调用本质上是异步的。这意味着返回数字的函数现在将返回一个数字的承诺。根据经验,如果您使用的是代理,请在其前面await 。另一侧将捕获并重新捕获例外。
Workercom.installTransfer(name, transferables)和Comlink.proxy默认情况下,从结构化克隆的意义上复制了每个函数参数,返回值和对象属性值。结构化克隆可以被认为是深层复制,但有一些局限性。有关详细信息,请参见此表。
如果您希望一个值被传输而不是复制(前提是该值是或包含Transferable值 - 您可以将值包装在installTransfer()调用中,并提供可转移值的列表:
import { installTransfer } from "workercom" ;
installTransfer < ArrayBuffer , string > ( "arraybuffer" , {
canHandle : ( value ) => value instanceof ArrayBuffer ,
serialize : ( value ) => [ _arrayBufferToBase64 ( value ) , [ ] ] ,
deserialize : ( { raw } ) => _base64ToArrayBuffer ( raw ) ,
} ) ;删除了Comlink.proxy() 。这将自动发生
// myProxy.onready = Comlink.proxy((data) => {
// /* ... */
// });
// * And now
myProxy . onready = ( data ) => {
/* ... */
}查看更多默认传输
通常,您想使用WorkerCom添加事件侦听器,其中事件源在另一个线程上:
button . addEventListener ( "click" , myProxy . onClick . bind ( myProxy ) ) ;虽然这不会立即投掷,但onClick永远不会被打电话给。这是因为Event既不是结构化的,也不是可转移的。作为解决方法,WorkerCom提供了转移处理程序。
每个函数参数和返回值都给出所有注册的传输处理程序。如果事件处理程序之一可以通过从canHandle()返回true来处理该值,则它现在负责将值序列化为结构化的可克隆数据并进行值。已在消息通道的两侧设置了转移处理程序。这是事件的转移处理程序的示例:
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 ,
} ) ;请注意,此特定的传输处理程序不会创建实际Event ,而只是一个具有event.target.id和event.target.classList属性的对象。通常,这已经足够了。如果不是,则可以轻松地扩大转移处理程序以提供所有必要的数据。
默认转换支持function , class , Error家族, TypedArray家庭家庭
Workercom.releaseProxy WorkerCom创建的每个代理都有[releaseProxy]方法。称其为从消息通道分离代理和暴露的对象,从而使两端都被收集。
const proxy = wrap ( port ) ;
// ... use the proxy ...
proxy [ releaseProxy ] ( ) ;Workercom.createEndpoint WorkerCom创建的每个代理都有[createEndpoint]方法。称其将返回一个新的MessagePort ,该消息已连接到与[createEndpoint]被调用的代理相同的对象。
const port = myProxy [ createEndpoint ] ( ) ;
const newProxy = wrap ( port ) ;Workercom.windowEndpoint(window, context = self, targetOrigin = "*") Windows和Web工人的postMessage有略有不同的变体。如果要使用WorkerCom与iFrame或其他窗口进行通信,则需要使用windowEndpoint()包装它。
window是应与之通信的窗口。 context是可以接收窗口消息window EventTarget (通常是self )。 targetOrigin可以传递到postMessage ,并允许通过原点过滤消息。有关详细信息,请参阅文档以获取Window.postMessage 。
对于用法示例,请查看docs文件夹中的非工作人员示例。
WorkerCom确实提供打字稿类型。当您expose()类型T的某些东西时,相应的wrap()调用将返回类型Workercom.Remote<T> 。尽管现在已经在一段时间内对这种类型进行了战斗测试,但它是在最佳基础上实施的。有些细微差别很难在打字稿的类型系统中正确编码,甚至不可能。有时可能有必要强迫某种类型的使用as unknown as <type> 。
WorkerCom与Node的worker_threads模块一起使用。
许可证