Skip to content

WorkerClient

درخواست و پاسخ روی یک Web Worker. کارگرِ خام تنها «فرستادن پیام» و «گرفتن پیام» را می‌شناسد: دو کار را هم‌زمان بفرستید، دو پیام برمی‌گردد و راهی نیست بدانید کدام از آنِ کدام است. WorkerClient بر هر درخواست شناسه‌ای می‌کوبد و هر پاسخ را به Promiseِ خودش می‌رساند.

API

new WorkerClient(options)

پارامترتوضیحنوعپیش‌فرض
createاینکه کارگر چگونه ساخته شود() => Workerالزامی
isProgressآیا این پیام پیشرفت است؟ (درخواست را تعیین تکلیف نمی‌کند)(res) => booleanres.type === 'progress'
getProgressمحتوای پیشرفت را بیرون می‌کشد(res) => Progressres.progress
isErrorآیا این پیام خطاست؟(res) => booleanres.type === 'error'
getErrorMessageمتن خطا(res) => stringres.message
timeoutمهلت هر درخواست (میلی‌ثانیه)؛ تنها همان درخواست را رد می‌کندnumberندارد
عضوتوضیح
send(request, onProgress?, transfer?)یک درخواست می‌فرستد و چشم‌به‌راه پاسخش می‌ماند
dispose()کارگر را تمام می‌کند و هر چه در جریان است رد می‌کند
activeاینکه کارگر ساخته شده است یا نه
pendingCountشمار درخواست‌های در جریان

serveWorker(handler, options?) — سمت کارگر

همتایی که درون کارگر می‌دود. از هر درخواست operationId را می‌خواند، چشم‌به‌راه رسیدگی‌کنندهٔ شما می‌ماند و پاسخ را با همان شناسه پس می‌فرستد.

پارامترتوضیحنوع
handler(request, { progress }) => Response | Promise<Response>Function
options.scopeجایی که گوش می‌دهد. پیش‌فرض self است؛ برای یک درگاه یا آزمون آن را عوض کنیدobject
options.resultTypeمقدار type پاسخ، وقتی رسیدگی‌کننده چیزی جز شیء برگرداند. پیش‌فرض 'result'string

تابعی به نام stop برمی‌گرداند که شنونده را برمی‌دارد.

نمونه

js
import { WorkerClient } from 'ranuts';

const client = new WorkerClient({
  create: () => new Worker(new URL('./nlp.worker.ts', import.meta.url), { type: 'module' }),
});

await client.send({ type: 'load', modelId }, (p) => renderProgress(p.progress));
const { scores } = await client.send({ type: 'classify', lines });
client.dispose();

و سمت کارگر:

js
// nlp.worker.ts
import { serveWorker } from 'ranuts';

serveWorker(async (request, { progress }) => {
  if (request.type === 'load') {
    const device = await loadModel(request.modelId, (p) => progress(p));
    return { type: 'loaded', device };
  }
  return { type: 'result', scores: await classify(request.lines) };
});

یادداشت‌ها

  1. کارگر تنبلانه ساخته می‌شود، در نخستین send: کار سنگین نباید هم‌زمان با بارگذاری صفحه آغاز شود.
  2. پیام‌های پیشرفت درخواست را تعیین تکلیف نمی‌کنند، پس یک درخواست می‌تواند به‌روزرسانی‌های بسیاری بفرستد و باز هم در پایان یک بار برآورده شود.
  3. فروپاشی کارگر همهٔ درخواست‌های در جریان را رد می‌کند. خطای گرفته‌نشده درون کارگر operationId ندارد، پس نمی‌توان آن را به یک درخواست نسبت داد.
  4. dispose() تمام می‌کند و رد می‌کند؛ send بعدی کارگر را از نو می‌سازد.
  5. پایان مهلت تنها همان درخواست را رد می‌کند و کارگر زنده می‌ماند.
  6. برای بافرهای بزرگ از transfer استفاده کنید تا به‌جای رونوشت ساختاری، مالکیت جابه‌جا شود.
  7. serveWorker خطاهای پرتاب‌شدهٔ همگام را هم می‌گیرد. پرتاب همگام درون onmessage به رسیدگی‌کنندهٔ خطای کارگر می‌گریزد و در آن مسیر هیچ operationId همراه نیست؛ آنگاه کارخواه ناچار است به‌جای همان یکی که واقعاً شکست، همهٔ درخواست‌های در جریان را ناکام کند.
  8. اینکه هر دو نیمه با هم عرضه می‌شوند عمدی است. دست‌ساز نوشتنِ سمت کارگر همان جایی است که بازتاب شناسه و پوششِ خطا میان پروژه‌ها از هم دور می‌افتند.

منتشرشده تحت مجوز MIT.