Web Worker ใน TypeScript

Web Worker ใน TypeScript

บทความนี้อธิบายเกี่ยวกับ Web Workers ใน TypeScript

คุณสามารถเรียนรู้แนวคิดของ Web Workers และเคล็ดลับการใช้งานต่าง ๆ พร้อมตัวอย่าง

YouTube Video

Worker ใน TypeScript

ใน TypeScript, Worker เป็นกลไกสำหรับการประมวลผลในเบื้องหลังที่แยกจากเธรดหลัก โดยอาศัย JavaScript Web Workers API สิ่งนี้ช่วยให้การคำนวณที่ซับซ้อนและงานแบบ asynchronous ดำเนินการได้โดยไม่กระทบกับการทำงานของอินเทอร์เฟซผู้ใช้

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' สคริปต์ Worker จะถูกตีความว่าเป็น ES module ซึ่งทำให้คุณสามารถใช้ 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 อาจจำเป็นต้องใช้ bundlers เช่น Webpack หรือ Vite การใช้เครื่องมือเหล่านี้ช่วยให้สามารถจัดการ bundle สคริปต์ของ Worker ได้อย่างเหมาะสม และใช้งานได้จาก main thread

ตัวอย่างเช่น เมื่อใช้ Vite ให้ใช้ import.meta.url เพื่อนำเข้า Worker ได้อย่างถูกต้อง

1const worker = new Worker(new URL('./worker.ts', import.meta.url), { type: 'module' });
  • สิ่งนี้ช่วยให้มั่นใจว่าสคริปต์ Worker ที่ bundle แล้วถูกโหลดอย่างถูกต้อง ช่วยให้สามารถประมวลผลผ่าน Worker ได้

ข้อพิจารณาเกี่ยวกับการส่งข้อความและการทำงานพร้อมกัน

  1. การคัดลอกข้อมูล

    เมื่อส่งและรับข้อความระหว่าง main thread และ Worker thread ข้อมูลจะถูก คัดลอก เมื่อจัดการกับข้อมูลที่ซับซ้อน เช่น ออบเจ็กต์ จำเป็นต้องพิจารณาประสิทธิภาพในการทำงาน การแลกเปลี่ยนข้อมูลจำนวนมากบ่อยครั้งอาจทำให้ประสิทธิภาพลดลง

  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 ในเธรดหลักจะว่างเปล่า (byteLength เป็น 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 คุณสามารถจัดการข้อผิดพลาดโดยใช้ event 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};
  • โค้ดนี้ใช้เหตุการณ์ onerror เพื่อดักจับและจัดการข้อผิดพลาดที่เกิดขึ้นภายใน Worker

สรุป

การใช้ Worker ใน TypeScript ช่วยให้คุณสามารถดำเนินงานที่หนักในแบ็กกราวด์ได้ โดยยังคง main thread ทำงานได้อย่างราบรื่น ด้วยการใช้การกำหนดประเภท การแลกเปลี่ยนข้อความก็สามารถทำได้อย่างปลอดภัยและสอดคล้องกับประเภท ด้วยการใส่ใจในเรื่องการแลกเปลี่ยนข้อมูลและการจัดการ thread คุณสามารถปรับปรุงประสิทธิภาพและการทำงานพร้อมกันได้อย่างมีประสิทธิภาพ

คุณสามารถติดตามบทความข้างต้นโดยใช้ Visual Studio Code บนช่อง YouTube ของเรา กรุณาตรวจสอบช่อง YouTube ด้วย

YouTube Video