メインコンテンツへ移動

เนื้อหาภาษาไทย / タイ語のコンテンツ

システムガイド 内容確認済み

HTML5 Web Workers

บทนี้แนะนำ HTML5 Web Workers ซึ่งเป็นเทคโนโลยีที่ช่วยให้ JavaScript สามารถรันใน background thread ได้ ทำให้เว็บไซต์ตอบสนองได้ดีขึ้นแม้มีการประมวลผลหนักหน่วง โดย...

HTML5 Web Workers - มัลติเธรดสำหรับเว็บเบราว์เซอร์

ในบทเรียนก่อนหน้า เราได้สำรวจ HTML5 Web Storage ซึ่งเป็นวิธีที่ยอดเยี่ยมในการจัดเก็บข้อมูลในเครื่องของผู้ใช้ ในบทนี้ เราจะมาดู HTML5 Web Workers ซึ่งเป็นเทคโนโลยีที่ช่วยให้เราสามารถรัน JavaScript ใน background thread ได้อย่างอิสระ ทำให้เว็บไซต์ของเราตอบสนองได้ดีขึ้น แม้จะมีการประมวลผลที่หนักหน่วงเกิดขึ้นเบื้องหลังก็ตาม

ทำไมต้องใช้ Web Workers?

โดยปกติแล้ว JavaScript จะทำงานใน single thread ซึ่งหมายความว่าการประมวลผลที่ใช้เวลานาน เช่น การคำนวณที่ซับซ้อน การจัดการข้อมูลขนาดใหญ่ หรือการ render กราฟิก อาจทำให้ UI ของเว็บไซต์หยุดชะงักหรือ "ค้าง" ไปชั่วขณะ Web Workers ช่วยแก้ไขปัญหานี้โดยการอนุญาตให้เราย้ายการประมวลผลเหล่านั้นไปยัง background thread ซึ่งจะไม่ส่งผลกระทบต่อ responsiveness ของ UI

การสร้าง Web Worker

การสร้าง Web Worker นั้นค่อนข้างง่าย สิ่งที่เราต้องมีคือไฟล์ JavaScript แยกต่างหาก ซึ่งจะประกอบด้วยโค้ดที่เราต้องการให้รันใน background thread จากนั้น เราจะสร้าง instance ของ Web Worker ใน main thread และกำหนดไฟล์ JavaScript นั้นให้กับ instance นั้น

ตัวอย่าง:

worker.js (ไฟล์ JavaScript สำหรับ Web Worker):

// worker.js
self.addEventListener('message', function(e) {
  const data = e.data;
  console.log('Worker: Message received from main script');

  // จำลองการคำนวณที่ใช้เวลานาน
  let result = 0;
  for (let i = 0; i < data; i++) {
    result += i;
  }

  self.postMessage(result);
  console.log('Worker: Posting message back to main script');
});

index.html (ไฟล์ HTML หลัก):

<!DOCTYPE html>
<html>
<head>
  <title>Web Workers Example</title>
</head>
<body>
  <h1>Web Workers Example</h1>
  <button id="startButton">Start Calculation</button>
  <p>Result: <span id="result"></span></p>

  <script>
    const startButton = document.getElementById('startButton');
    const resultElement = document.getElementById('result');

    if (window.Worker) {
      const myWorker = new Worker('worker.js');

      startButton.onclick = function() {
        const number = 100000000; // จำนวน iterations ที่เยอะเพื่อจำลองการทำงานนาน
        myWorker.postMessage(number);
        console.log('Main script: Message posted to worker');
      }

      myWorker.onmessage = function(e) {
        resultElement.textContent = e.data;
        console.log('Main script: Message received from worker');
      }

      myWorker.onerror = function(e) {
        console.log('Main script: Error occurred in worker: ' + e.message);
      }

    } else {
      console.log('Your browser doesn\'t support web workers.');
    }
  </script>
</body>
</html>

คำอธิบาย:

  • ในไฟล์ worker.js เราใช้ self.addEventListener('message', function(e) { ... }); เพื่อรับ messages จาก main thread และ self.postMessage(result); เพื่อส่ง messages กลับไปยัง main thread
  • ในไฟล์ index.html เราสร้าง instance ของ Web Worker โดยใช้ new Worker('worker.js');
  • เราใช้ myWorker.postMessage(number); เพื่อส่งข้อมูลไปยัง Web Worker และ myWorker.onmessage = function(e) { ... }; เพื่อรับข้อมูลกลับจาก Web Worker
  • เราใช้ myWorker.onerror = function(e) { ... }; เพื่อจัดการกับข้อผิดพลาดที่เกิดขึ้นใน Web Worker

การส่งข้อมูลระหว่าง Main Thread และ Web Worker

Web Workers สื่อสารกับ main thread โดยใช้ message passing ซึ่งหมายความว่าข้อมูลจะถูกส่งเป็น messages แทนที่จะแชร์ memory โดยตรง วิธีนี้ช่วยป้องกันปัญหา race condition และทำให้โค้ดปลอดภัยยิ่งขึ้น

เราใช้ postMessage() method เพื่อส่งข้อมูล และ onmessage event handler เพื่อรับข้อมูล ทั้ง main thread และ Web Worker สามารถใช้ methods เหล่านี้ได้

ประเภทข้อมูลที่สามารถส่งได้:

  • Primitive types (string, number, boolean, null, undefined)
  • Plain JavaScript objects
  • Arrays
  • Transferable objects (ArrayBuffer, MessagePort, ImageBitmap)

Transferable Objects:

Transferable objects คือ objects ที่สามารถ "ถ่ายโอน" ownership ไปยัง Web Worker ได้ เมื่อ object ถูกถ่ายโอนแล้ว main thread จะไม่สามารถเข้าถึง object นั้นได้อีกต่อไป วิธีนี้มีประสิทธิภาพมากกว่าการ copy ข้อมูล เนื่องจากไม่จำเป็นต้องสร้างสำเนาของข้อมูล

ข้อจำกัดของ Web Workers

แม้ว่า Web Workers จะมีประโยชน์อย่างมาก แต่ก็มีข้อจำกัดบางประการที่เราควรทราบ:

  • DOM Access: Web Workers ไม่สามารถเข้าถึง DOM ได้โดยตรง ซึ่งหมายความว่าเราไม่สามารถใช้ Web Workers เพื่อแก้ไข HTML elements ได้โดยตรง เราต้องส่งข้อมูลกลับไปยัง main thread และให้ main thread ทำการแก้ไข DOM
  • Window Object: Web Workers ไม่สามารถเข้าถึง window object ได้ ซึ่งหมายความว่าเราไม่สามารถใช้ window.alert(), window.confirm() หรือ window.location ใน Web Workers
  • Global Variables: Web Workers มี global scope ของตัวเอง ซึ่งแตกต่างจาก main thread ดังนั้น global variables ที่กำหนดใน main thread จะไม่สามารถเข้าถึงได้ใน Web Worker และในทางกลับกัน
  • File Access: การเข้าถึงไฟล์โดยตรงอาจถูกจำกัด ขึ้นอยู่กับเบราว์เซอร์และนโยบายความปลอดภัย

การใช้งาน Web Workers ในงานที่ใช้เวลานาน

Web Workers เหมาะอย่างยิ่งสำหรับงานที่ใช้เวลานานและอาจทำให้ UI หยุดชะงัก ตัวอย่างเช่น:

  • Image Processing: การปรับขนาด, การกรอง, หรือการแปลงภาพ
  • Data Analysis: การประมวลผลข้อมูลขนาดใหญ่, การสร้างกราฟ, หรือการคำนวณทางสถิติ
  • Cryptographic Operations: การเข้ารหัสหรือถอดรหัสข้อมูล
  • Physics Simulations: การจำลองการเคลื่อนที่ของวัตถุ
  • Ray Tracing: การสร้างภาพสามมิติจากแสงและเงา

ตัวอย่าง: Image Processing

สมมติว่าเราต้องการปรับขนาดภาพขนาดใหญ่ในเว็บไซต์ของเรา หากเราทำการปรับขนาดภาพใน main thread อาจทำให้ UI หยุดชะงัก ในทางกลับกัน เราสามารถใช้ Web Worker เพื่อทำการปรับขนาดภาพใน background thread ได้

index.html (ไฟล์ HTML หลัก):

<!DOCTYPE html>
<html>
<head>
  <title>Web Worker Image Processing</title>
</head>
<body>
  <h1>Web Worker Image Processing</h1>
  <input type="file" id="imageInput">
  <canvas id="outputCanvas"></canvas>

  <script>
    const imageInput = document.getElementById('imageInput');
    const outputCanvas = document.getElementById('outputCanvas');
    const ctx = outputCanvas.getContext('2d');

    if (window.Worker) {
      const imageWorker = new Worker('imageWorker.js');

      imageInput.addEventListener('change', function(e) {
        const file = e.target.files[0];
        const reader = new FileReader();

        reader.onload = function(event) {
          const img = new Image();
          img.onload = function() {
            // ส่ง ImageBitmap ไปยัง Web Worker
            createImageBitmap(img).then(bitmap => {
              imageWorker.postMessage({ image: bitmap, width: 200, height: 150 }, [bitmap]); // Transferable object
            });
          }
          img.src = event.target.result;
        }
        reader.readAsDataURL(file);
      });

      imageWorker.onmessage = function(e) {
        const imageData = e.data.imageData;
        const width = e.data.width;
        const height = e.data.height;

        outputCanvas.width = width;
        outputCanvas.height = height;
        ctx.putImageData(imageData, 0, 0);
      }

      imageWorker.onerror = function(e) {
        console.log('Error occurred in worker: ' + e.message);
      }

    } else {
      console.log('Your browser doesn\'t support web workers.');
    }
  </script>
</body>
</html>

imageWorker.js (ไฟล์ JavaScript สำหรับ Web Worker):

self.addEventListener('message', function(e) {
  const imageBitmap = e.data.image;
  const width = e.data.width;
  const height = e.data.height;

  const offscreenCanvas = new OffscreenCanvas(width, height);
  const offscreenCtx = offscreenCanvas.getContext('2d');
  offscreenCtx.drawImage(imageBitmap, 0, 0, width, height);

  const imageData = offscreenCtx.getImageData(0, 0, width, height);

  self.postMessage({ imageData: imageData, width: width, height: height }, [imageData.data.buffer]); // Transferable object
});

คำอธิบาย:

  • เราใช้ createImageBitmap() เพื่อสร้าง ImageBitmap จาก Image object และส่ง ImageBitmap ไปยัง Web Worker เป็น Transferable object
  • ใน Web Worker เราใช้ OffscreenCanvas เพื่อ render ImageBitmap ลงบน canvas และดึง ImageData ออกมา
  • เราส่ง ImageData กลับไปยัง main thread เป็น Transferable object โดยส่งเฉพาะ imageData.data.buffer เพื่อประสิทธิภาพสูงสุด
  • ใน main thread เราใช้ ctx.putImageData() เพื่อแสดง ImageData บน canvas

สรุป

HTML5 Web Workers เป็นเครื่องมือที่มีประสิทธิภาพสำหรับการเพิ่มประสิทธิภาพของเว็บไซต์โดยการรัน JavaScript ใน background thread ช่วยให้เราสามารถจัดการกับงานที่ใช้เวลานานโดยไม่ทำให้ UI หยุดชะงัก แม้จะมีข้อจำกัดบางประการ แต่ Web Workers ก็เป็นส่วนเสริมที่ยอดเยี่ยมสำหรับชุดเครื่องมือของนักพัฒนาเว็บ

ในบทถัดไป เราจะมาสำรวจ HTML5 Drag and Drop API ซึ่งเป็นวิธีที่ง่ายและสะดวกในการเพิ่มฟังก์ชันการลากและวางให้กับเว็บไซต์ของเรา

Office.in.th Custom Service

この構成をもとにシステムを開発・カスタマイズしたいですか?

Office.in.th は、エンタープライズ Web アプリケーション、API 連携、官民の業務管理システムの設計・開発を承り、長期的なサポートも提供します。

ソフトウェア開発サービスを見る