WorkerCom يجعل عمال الويب ممتعًا. Workercom هي مكتبة صغيرة (1.1 كيلو بايت) ، تزيل الحاجز العقلي للتفكير في postMessage ويخفي حقيقة أنك تعمل مع العمال. إعادة كتابة وتحسين قضايا الاتصال من ComLink
على مستوى أكثر تجريدًا ، يعد تطبيق RPC لوكلاء postMessage و ES6.
$ yarn add workercom
Comlink.proxy غير ضرورية (ستجد WorkerCom وظائف ، ونقلها وترطيبها)function ، class ، عائلة Error ، عائلة TypedArray وغيرها يمكن للمتصفحات بدون دعم وكيل ES6 استخدام الوكيل.
الحجم : ~ 2.5k ، ~ 1.2k gzip'd ، ~ 1.1k brotli'd
على الهواتف المحمولة ، وخاصة على الهواتف المحمولة المنخفضة ، من المهم الحفاظ على الخيط الرئيسي قدر الإمكان حتى يتمكن من الاستجابة لتفاعلات المستخدم بسرعة وتوفير تجربة خالية من Jank. يجب أن يكون موضوع واجهة المستخدم لعمل واجهة المستخدم فقط . عمال الويب هم واجهة برمجة تطبيقات الويب التي تتيح لك تشغيل الرمز في مؤشر ترابط منفصل. للتواصل مع موضوع آخر ، يقدم عمال الويب واجهة برمجة تطبيقات 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 ( ) ;العامل
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 عند استخدام WorkerCom مع SharedWorker عليك أن:
port ، لمثيل SharedWorker ، عند استدعاء Workercom.wrap .Workercom.expose ضمن رد اتصال onconnect للعامل المشترك.نصيحة للمحترفين: يمكنك الوصول إلى DevTools لأي عامل مشترك يعمل حاليًا في Chrom
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 عن 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() ، فسيكون الآن مسؤولاً عن تسلسل القيمة إلى البيانات القابلة للاستنساخ منظمة وللتعرف على القيمة. تم إعداد معالج النقل على جانبي قناة الرسائل. إليك مثال معالج نقل الأحداث:
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 and Web Commore متغيرات مختلفة قليلاً من postMessage . إذا كنت ترغب في استخدام WorkerCom للتواصل مع iframe أو نافذة أخرى ، فأنت بحاجة إلى لفها باستخدام windowEndpoint() .
window هي النافذة التي ينبغي التواصل معها. context هو EventTarget الذي يمكن استلام الرسائل من window (في كثير من الأحيان self ). يتم تمرير targetOrigin إلى postMessage ويسمح بتصفية الرسائل حسب الأصل. للحصول على التفاصيل ، راجع الوثائق لـ Window.postMessage .
للحصول على مثال للاستخدام ، ألقِ نظرة على أمثلة غير العاملة في مجلد docs .
يوفر Workercom أنواعًا من أنواع الأنواع. عندما expose() شيء من النوع T ، ستعيد استدعاء wrap() المقابل شيئًا من نوع Workercom.Remote<T> . على الرغم من أن هذا النوع قد تم اختباره في المعركة على مدار بعض الوقت الآن ، إلا أنه يتم تنفيذه على أساس أفضل للجهد. هناك بعض الفروق الدقيقة التي من الصعب للغاية إن لم يكن مستحيل تشفيرها بشكل صحيح في نظام نوع TypeScript. قد يكون من الضروري في بعض الأحيان فرض نوع معين باستخدام as unknown as <type> .
يعمل WorkerCom مع وحدة Node's worker_threads .
ترخيص معهد ماساتشوستس للتكنولوجيا