Web Worker ב-TypeScript

Web Worker ב-TypeScript

מאמר זה מסביר על Web Workers ב-TypeScript.

ניתן ללמוד על הקונספט של Web Workers וטיפים שונים לשימוש עם דוגמאות.

YouTube Video

Worker ב-TypeScript

ב-TypeScript, Worker הוא מנגנון לעיבוד ברקע, נפרד מהשורה הראשית, תוך שימוש ב-API של JavaScript Web Workers. דבר זה מאפשר ביצוע חישובים כבדים ומשימות אסינכרוניות מבלי להשפיע על תפעול ממשק המשתמש.

Worker פועל במקביל להשורה הראשית (UI thread) ויכול להחליף נתונים בין השורות באמצעות הודעות. גם ב-TypeScript, ניתן להשתמש ב-Worker תוך כתיבת קוד עם בטיחות טיפוסים.

שימוש בסיסי ב-Worker

  1. יצירת Worker

    צרו מופע Worker והריצו את הסקריפט המוגדר. בד״כ הסקריפט מוגדר בקובץ נפרד.

  2. החלפת הודעות

    שלחו וקבלו הודעות בין השורה הראשית לשורת ה-Worker באמצעות postMessage ו-onmessage.

דוגמא: מימוש בסיסי של Worker

  1. worker.ts: סקריפט עבור Worker
1// worker.ts
2self.onmessage = (event) => {
3    const data = event.data;
4    const result = data.num1 + data.num2;
5    self.postMessage(result); // Return the result to the main thread
6};
  1. main.ts: סקריפט לשימוש ב-Worker בשורה הראשית
 1// main.ts
 2const worker = new Worker(
 3    new URL('./worker.ts', import.meta.url),
 4    { type: 'module' }
 5);
 6
 7worker.onmessage = (event) => {
 8    console.log("Result from worker:", event.data); // Receive message from the worker
 9};
10
11worker.postMessage({ num1: 10, num2: 20 }); // Send message to the worker
  • בדוגמא זו, worker.ts פועל בשורה נפרדת, מחשב את סכום num1 ו-num2, ומחזיר את התוצאה לשורה הראשית. השורה הראשית מקבלת את התוצאה ומציגה אותה בקונסול.
  • כאשר אתה מציין ‎type: 'module'‎, קובץ הסקריפט של העובד מפורש כמודול ES, מה שמאפשר להשתמש ב‑‎import‎ ו‑‎export‎. זה מאפשר לך לטפל במבני מודולים מבלי להשתמש ב‑‎importScripts()‎ המסורתי.

נקודות למחשבה בעת שימוש ב-Workers ב-TypeScript

הוספת הגדרות טיפוסים

ב-TypeScript, יש להגדיר טיפוסי נתונים כדי להבטיח אינטראקציה בטוחה של טיפוסים בעת שליחת וקבלת הודעות.

 1// Define data types
 2interface WorkerData {
 3    num1: number;
 4    num2: number;
 5}
 6
 7interface WorkerResult {
 8    result: number;
 9}
10
11// worker.ts
12self.onmessage = (event: MessageEvent<WorkerData>) => {
13    const data = event.data;
14    const result = data.num1 + data.num2;
15    const message: WorkerResult = { result };
16    self.postMessage(message); // Send the result in a type-safe manner
17};
18
19// main.ts
20const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
21
22// Type the event from the worker
23worker.onmessage = (event: MessageEvent<WorkerResult>) => {
24  console.log("Result from worker:", event.data); // event.data is number
25};
26
27// Send typed data to the worker
28const message: WorkerData = { num1: 10, num2: 20 };
29worker.postMessage(message);
  • על ידי ציון פרמטר הטיפוס של MessageEvent, ניתן להגדיר בבירור את סוג הנתונים שיש לקבל. דבר זה מאפשר חילופי נתונים עם בטיחות טיפוסים.

הגדרת Webpack או Vite

כאשר משתמשים ב-Worker ב-TypeScript, ייתכן שיהיה צורך בשימוש בכלים כמו Webpack או Vite. באמצעות הכלים הללו, תוכלו לאגד (bundle) כראוי את קובץ ה-Worker ולאפשר גישה אליו מה-Thread הראשי.

לדוגמה, כאשר משתמשים ב-Vite, השתמשו ב-import.meta.url כדי לייבא את ה-Worker כהלכה.

1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
  • זה מבטיח שקובץ ה-Worker המאוגד ייטען כראוי, ובכך יתאפשר עיבוד באמצעות ה-Worker.

שיקולים להודעות ופעולה בו-זמנית

  1. העתקת נתונים

    בעת שליחת וקבלת הודעות בין ה-Thread הראשי ל-Thread של ה-Worker, הנתונים מועתקים. בעת עבודה עם נתונים מורכבים כגון אובייקטים, יש להתחשב ביעילות. החלפה תכופה של כמויות גדולות של נתונים עלולה לפגוע בביצועים.

  2. עצמים ניתנים להעברה (Transferable)

    חלק מהאובייקטים, כגון ArrayBuffer, נקראים אובייקטים 'הניתנים להעברה' (Transferable). אובייקטים שניתנים להעברה (Transferable) יכולים להיות מועברים ל-Worker במקום להיות מועתקים בזמן שליחת מסרים. שיטה זו מאפשרת לך להימנע מעומס נוסף שנובע מהעתקת נתונים.

1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
2
3const buffer = new ArrayBuffer(1024);
4worker.postMessage(buffer, [buffer]); // Transfer ownership to the Worker
5
6console.log(buffer.byteLength); // 0 (ownership moved)
  • על ידי העברת [buffer] כארגומנט השני ל-worker.postMessage(), ה-buffer מועבר ל-Worker במקום להיות מועתק.

  • לאחר מכן, ה-buffer בתהליך הראשי מתאפס (עם אורך ביתים 0) ויכול לשמש רק את ה-Worker.

סיום שימוש ב-Worker

יש לסיים את פעולתו של ה-Worker לאחר השימוש כדי לצמצם את צריכת הזיכרון. ניתן לסיים פעולתו של ה-Worker באמצעות הפונקציה terminate.

1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
2// ...
3
4worker.terminate(); // Terminate the Worker
  • קוד זה מסיים את ה-Worker באמצעות המתודה terminate.

טיפול בשגיאות ב-Worker

אם מתרחשת שגיאה בתוך ה-Worker, ניתן לטפל בה באמצעות האירוע onerror.

1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
2
3worker.onerror = (error) => {
4    console.error("Error in Worker:", error.message);
5};
  • קוד זה לוכד ומטפל בשגיאות שמתרחשות בתוך ה-Worker באמצעות אירוע onerror.

סיכום

על ידי שימוש ב-Worker ב-TypeScript, ניתן לבצע משימות כבדות ברקע תוך שמירה על חלקות ה-Thread הראשי. באמצעות שימוש בהגדרות סוגים (type definitions), ניתן לבצע החלפת הודעות באופן בטוח מבחינת סוגים (type-safe). על ידי תשומת לב לניהול חילופי נתונים ו-Threads, ניתן להשיג שיפורי ביצועים ויעילות בפעולה בו-זמנית.

תוכלו לעקוב אחר המאמר שלמעלה באמצעות Visual Studio Code בערוץ היוטיוב שלנו. נא לבדוק גם את ערוץ היוטיוב.

YouTube Video