WorkerCom ทำให้นักเขียนเว็บสนุก Workercom เป็น ห้องสมุดเล็ก ๆ (1.1KB) ซึ่งจะขจัดอุปสรรคทางจิตของการคิดเกี่ยวกับ postMessage และซ่อนความจริงที่ว่าคุณกำลังทำงานกับคนงาน เขียนใหม่และปรับปรุงปัญหาการสื่อสารจาก Comlink
ในระดับที่เป็นนามธรรมมากขึ้นมันคือการใช้งาน RPC สำหรับ postMessage และ proxies ES6
$ yarn add workercom
Comlink.proxy ที่ไม่จำเป็น (WorkerCom จะค้นหาฟังก์ชั่นการถ่ายโอนและให้ความชุ่มชื้น)function class ครอบครัว Error ครอบครัว TypedArray และอื่น ๆ เบราว์เซอร์ที่ไม่มีการสนับสนุนพร็อกซี ES6 สามารถใช้พร็อกซี-โพลีฟิลด์
ขนาด : ~ 2.5k, ~ 1.2k gzip'd, ~ 1.1k brotli'd
บนโทรศัพท์มือถือและโดยเฉพาะอย่างยิ่งในโทรศัพท์มือถือต่ำสุดเป็นสิ่งสำคัญที่จะต้องทำให้เธรดหลักไม่ได้ใช้งานมากที่สุดเพื่อให้สามารถตอบสนองต่อการโต้ตอบของผู้ใช้ได้อย่างรวดเร็ว กระทู้ UI ควรใช้งาน UI เท่านั้น Webworkers เป็นเว็บ API ที่อนุญาตให้คุณเรียกใช้รหัสในเธรดแยกต่างหาก ในการสื่อสารกับเธรดอื่นผู้เขียนเว็บเสนอ API postMessage คุณสามารถส่งวัตถุ JavaScript เป็นข้อความโดยใช้ myWorker.postMessage(someObject) เรียกเหตุการณ์ message ภายในคนงาน
WorkerCom เปลี่ยน API ที่ใช้ข้อความนี้ให้กลายเป็นสิ่งที่เป็นมิตรกับนักพัฒนาซอฟต์แวร์มากขึ้นโดยการให้การใช้งาน RPC: ค่าจากเธรดหนึ่งสามารถใช้ภายในเธรดอื่น ๆ (และในทางกลับกัน) เช่นเดียวกับค่าท้องถิ่น
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 ( ) ;Worker.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 ( ) ;Worker.js
import { expose } from "workercom" ;
async function remoteFunction ( cb ) {
await cb ( "A string from a worker" ) ;
}
expose ( remoteFunction ) ;SharedWorker เมื่อใช้ WorkerCom กับ SharedWorker ที่คุณต้องทำ:
port ของอินสแตนซ์ SharedWorker เมื่อโทรหา Workercom.wrapWorkercom.expose ภายในการโทรกลับของผู้ปฏิบัติงาน onconnect ใช้ร่วมกันเคล็ดลับสำหรับมืออาชีพ: คุณสามารถเข้าถึง Devtools สำหรับคนงานที่ใช้ร่วมกันที่ทำงานอยู่ใน Chrome โดยไปที่: Chrome: // ตรวจสอบ/#คนงาน
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 ( ) ;Worker.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) และ Workercom.expose(value, endpoint?) เป้าหมายของ WorkerCom คือการทำให้ค่า ที่เปิดเผย จากเธรดหนึ่งที่มีอยู่ในอีกเธรด expose value ที่เปิดเผยบน endpoint โดยที่ 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 เสนอตัวจัดการการถ่ายโอน
แต่ละพารามิเตอร์ฟังก์ชั่นและค่าส่งคืนจะมอบให้กับตัวจัดการการถ่ายโอนที่ลงทะเบียน ทั้งหมด หากหนึ่งในตัวจัดการเหตุการณ์ส่งสัญญาณว่าสามารถประมวลผลค่าได้โดยการส่งคืน true จาก canHandle() ตอนนี้จะต้องรับผิดชอบในการจัดลำดับค่าให้กับข้อมูล cloneable ที่มีโครงสร้างและเพื่อลดค่า มีการตั้งค่าตัวจัดการการถ่ายโอน ทั้งสองด้าน ของช่องข้อความ นี่คือตัวอย่างตัวจัดการการถ่ายโอนสำหรับกิจกรรม:
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 Workers มี postMessage ที่แตกต่างกันเล็กน้อย หากคุณต้องการใช้ WorkerCom เพื่อสื่อสารกับ IFRAME หรือหน้าต่างอื่นคุณต้องห่อด้วย windowEndpoint()
window เป็นหน้าต่างที่ควรสื่อสารด้วย context คือ EventTarget ที่ข้อความ จาก window สามารถรับได้ (มักจะ self ) targetOrigin จะถูกส่งผ่านไปยัง postMessage และอนุญาตให้กรองข้อความตามแหล่งกำเนิด สำหรับรายละเอียดดูเอกสารประกอบสำหรับ Window.postMessage
สำหรับตัวอย่างการใช้งานลองดูตัวอย่างที่ไม่ใช่คนงานในโฟลเดอร์ docs
WorkerCom มีประเภท typescript เมื่อคุณ expose() บางสิ่งบางอย่าง T Type T การโทรที่เกี่ยวข้อง wrap() จะส่งคืนสิ่งที่เป็นของ Workercom.Remote<T> ในขณะที่ประเภทนี้ได้รับการทดสอบการต่อสู้มาระยะหนึ่งแล้ว แต่ก็ถูกนำไปใช้อย่างดีที่สุด มีความแตกต่างบางอย่างที่ยากอย่างไม่น่าเชื่อหากไม่สามารถเข้ารหัสได้อย่างถูกต้องในระบบประเภทของ TypeScript บางครั้ง อาจ จำเป็นต้องบังคับให้บางประเภทโดยใช้ as unknown as <type>
WorkerCom ทำงานร่วมกับโมดูล worker_threads ของ Node
ใบอนุญาต MIT