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模塊一起使用。
許可證