ווב וורקרס בג'אווה סקריפט

ווב וורקרס בג'אווה סקריפט

מאמר זה מסביר את ווב וורקרס בג'אווה סקריפט.

YouTube Video

javascript-web-worker.html
  1<!DOCTYPE html>
  2<html lang="en">
  3<head>
  4  <meta charset="UTF-8">
  5  <title>JavaScript &amp; HTML</title>
  6  <style>
  7    * {
  8        box-sizing: border-box;
  9    }
 10
 11    body {
 12        margin: 0;
 13        padding: 1em;
 14        padding-bottom: 10em;
 15        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 16        background-color: #f7f9fc;
 17        color: #333;
 18        line-height: 1.6;
 19    }
 20
 21    .container {
 22        max-width: 800px;
 23        margin: 0 auto;
 24        padding: 1em;
 25        background-color: #ffffff;
 26        border: 1px solid #ccc;
 27        border-radius: 10px;
 28        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 29    }
 30
 31    .container-flex {
 32        display: flex;
 33        flex-wrap: wrap;
 34        gap: 2em;
 35        max-width: 1000px;
 36        margin: 0 auto;
 37        padding: 1em;
 38        background-color: #ffffff;
 39        border: 1px solid #ccc;
 40        border-radius: 10px;
 41        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
 42    }
 43
 44    .left-column, .right-column {
 45        flex: 1 1 200px;
 46        min-width: 200px;
 47    }
 48
 49    h1, h2 {
 50        font-size: 1.2rem;
 51        color: #007bff;
 52        margin-top: 0.5em;
 53        margin-bottom: 0.5em;
 54        border-left: 5px solid #007bff;
 55        padding-left: 0.6em;
 56        background-color: #e9f2ff;
 57    }
 58
 59    button {
 60        display: block;
 61        margin: 1em auto;
 62        padding: 0.75em 1.5em;
 63        font-size: 1rem;
 64        background-color: #007bff;
 65        color: white;
 66        border: none;
 67        border-radius: 6px;
 68        cursor: pointer;
 69        transition: background-color 0.3s ease;
 70    }
 71
 72    button:hover {
 73        background-color: #0056b3;
 74    }
 75
 76    #output {
 77        margin-top: 1em;
 78        background-color: #1e1e1e;
 79        color: #0f0;
 80        padding: 1em;
 81        border-radius: 8px;
 82        min-height: 200px;
 83        font-family: Consolas, monospace;
 84        font-size: 0.95rem;
 85        overflow-y: auto;
 86        white-space: pre-wrap;
 87    }
 88
 89    .highlight {
 90        outline: 3px solid #ffc107; /* yellow border */
 91        background-color: #fff8e1;  /* soft yellow background */
 92        transition: background-color 0.3s ease, outline 0.3s ease;
 93    }
 94
 95    .active {
 96        background-color: #28a745; /* green background */
 97        color: #fff;
 98        box-shadow: 0 0 10px rgba(40, 167, 69, 0.5);
 99        transition: background-color 0.3s ease, box-shadow 0.3s ease;
100    }
101  </style>
102</head>
103<body>
104    <div class="container">
105        <h1>JavaScript Console</h1>
106        <button id="executeBtn">Execute</button>
107        <div id="output"></div>
108    </div>
109
110    <script>
111        // Override console.log to display messages in the #output element
112        (function () {
113            // Override console.log
114            const originalLog = console.log;
115            console.log = function (...args) {
116                originalLog.apply(console, args);
117                const message = document.createElement('div');
118                message.textContent = args.map(String).join(' ');
119                output.appendChild(message);
120            };
121
122            // Override console.error
123            const originalError = console.error;
124            console.error = function (...args) {
125                originalError.apply(console, args);
126                const message = document.createElement('div');
127                message.textContent = args.map(String).join(' ');
128                message.style.color = 'red'; // Color error messages red
129                output.appendChild(message);
130            };
131        })();
132
133        document.getElementById('executeBtn').addEventListener('click', () => {
134            // Prevent multiple loads
135            if (document.getElementById('externalScript')) return;
136
137            const script = document.createElement('script');
138            script.src = 'javascript-web-worker.js';
139            script.id = 'externalScript';
140            //script.onload = () => console.log('javascript-web-worker.js loaded and executed.');
141            //script.onerror = () => console.log('Failed to load javascript-web-worker.js.');
142            document.body.appendChild(script);
143        });
144    </script>
145</body>
146</html>

Web Worker ב-JavaScript

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

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

בואו נסתכל על השימוש הבסיסי ב-‏Web Worker.

יוצרים Web Worker חדש על-ידי ציון קובץ JavaScript.

1// worker.js (created as a separate file)
2onmessage = function(event) {
3    // Receive a message
4    const data = event.data;
5    // Perform heavy computation or processing
6    const result = data * 2;
7    // Return the result to the main thread
8    postMessage(result);
9};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js');
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};
  • הקוד הזה מדגים את המנגנון הבסיסי של שימוש ב-Web Worker לשליחת בקשת חישוב מהתהליך הראשי ולקבלת תוצאה בצורה אסינכרונית. הוא שולח את הערך 10 כהודעה ל-Web Worker ומקבל את הערך 20 כהודעת תוצאה. התהליך הראשי ו-Web Worker מתקשרים על-ידי שליחת וקבלת הודעות כדי לבקש ולקבל תוצאות עיבוד.

פונקציות בסיסיות

‏Web Worker מספק את הפיצ'רים הבסיסיים הבאים.

  • postMessage ו-onmessage משמשים לשליחת וקבלת הודעות בין התהליך הראשי ל-Web Worker. שולחים נתונים עם postMessage ומקבלים עם onmessage.
  • עצמאות תהליכים (Thread Independence) ‏Web Worker פועל באופן עצמאי לחלוטין מהתהליך הראשי. לכן, לא ניתן לגשת למשתנים ופונקציות המוגדרים בתהליך הראשי. נתונים נדרשים צריכים לעבור דרך postMessage.
  • ייבוא סקריפטים (Script Import) כדי לטעון סקריפטים חיצוניים בתוך Web Worker, משתמשים ב-importScripts().
1// mathUtils.js
2function double(n) {
3    return n * 2;
4}
1// worker.js
2importScripts('mathUtils.js');
3
4onmessage = function(event) {
5    const input = event.data;
6    const result = double(input); // mathUtils.jsの関数を使用
7    postMessage(result);
8};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js');
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};

לחלופין, אפשר גם להשתמש ב-import כמו שמוצג למטה.

1// lib.js
2
3// Simulated CPU-intensive task
4export function doHeavyWork(n) {
5    return n * 2;
6}
1// worker.js
2import { doHeavyWork } from './lib.js';
3
4self.onmessage = (event) => {
5  const data = event.data;
6  const result = doHeavyWork(data);
7  self.postMessage(result);
8};
 1// Main thread (main.js)
 2const worker = new Worker('worker.js', { type: 'module' });
 3
 4// Send a message to the worker
 5worker.postMessage(10);
 6
 7// Receive a message from the worker
 8worker.onmessage = function(event) {
 9    console.log('Result from Worker: ', event.data); // Result: 20
10};
11
12// Error handling
13worker.onerror = function(error) {
14    console.error('Worker error: ', error);
15};
  • על-ידי ציון type: 'module' בארגומנט של new Worker, ניתן להתייחס ל-worker כמודול ES ולהשתמש בתחביר import.

הבדלים בין Web Worker לפונקציות async

Web Worker

תכונות
  • בידוד תהליכים (Thread Isolation) ‏Web Worker מריץ קוד JavaScript בתהליך נפרד. זה מאפשר לבצע חישובים כבדים מבלי לחסום את התהליך הראשי (תהליך ממשק המשתמש).
  • עיבוד מקבילי (Concurrent Processing) שימוש ב-Web Worker מאפשר לתוכניות JavaScript לבצע עיבוד מקבילי בתהליכים מרובים.
  • תקשורת הודעות (Message Communication) ‏Web Worker והתהליך הראשי אינם משתפים נתונים ישירות ומתקשרים באמצעות postMessage ו-onmessage.
  • אין גישה ל-UI (Cannot Access UI) ‏Web Worker לא יכול לגשת ל-DOM ולכן לא יכול לשנות את ה-UI ישירות.
מקרי שימוש
  • הוא מתאים לעיבודים כבדים כמו עיבוד תמונה, ניתוח נתונים והצפנה.
  • ניתן להשתמש בו כאשר אינך רוצה לחסום את התהליך הראשי.

async

תכונות
  • פישוט עיבוד אסינכרוני (Simplifying Asynchronous Processing) פונקציית async היא תחביר שנועד להקל על קריאות של עיבוד אסינכרוני, ומשתמשת ב-Promise מאחורי הקלעים.
  • תהליך יחיד (Single Thread) כל פונקציות ה-async רצות על התהליך הראשי. לכן, יש להמציא דרכים להימנע מחסימת תהליך ממשק המשתמש.
  • מתאים לפעולות קלט/פלט (Optimal for I/O Operations) הוא מתאים למשימות אסינכרוניות כמו תקשורת רשת וקריאת קבצים, אך לא לעיבוד כבד.
מקרי שימוש
  • הוא מתאים לתקשורת רשת כמו קריאות API.
  • הוא מתאים לקריאה וכתיבת קבצים באמצעות API של הדפדפן או Node.js.

הבדלים מרכזיים

תכונות Web Worker async
סביבת ביצוע תהליך נפרד תהליך ראשי
מטרה עיבוד מקבילי, פריקת עומסים כבדים מהמחשב הראשי תיאור תמציתי של פעולות אסינכרוניות
גישה ל-DOM לא אפשרי אפשרי
שיטת תקשורת העברת הודעות (לדוגמה, postMessage) לא נדרש (מבוצע דרך קריאות ישירות לפונקציות או await)
מקרי שימוש חישובים תובעניים בזמן, ניתוח נתונים פעולות I/O, קריאות API

מתי להשתמש בכל אחד מהם

למשימות תובעניות למעבד (CPU), ניתן להשתמש ב-Web Worker כדי להקטין את העומס על התהליך הראשי. מצד שני, עבור תקשורת רשת או פעולות I/O, ניתן לפשט את הקוד באמצעות async/await.

בשילוב נכון בין השניים, ניתן להשיג עיבוד אסינכרוני יעיל.

דוגמאות לשימוש ב-Web Worker

דוגמה לפריקת חישוב כבד

להלן דוגמה להעברת חישובים כבדים ל-Web Worker.

 1// worker.js
 2onmessage = function(event) {
 3    const num = event.data;
 4    const result = fibonacci(num);
 5    postMessage(result);
 6};
 7
 8function fibonacci(n) {
 9    if (n <= 1) return n;
10    return fibonacci(n - 1) + fibonacci(n - 2);
11}
1// Main thread
2const worker = new Worker('worker.js');
3
4worker.onmessage = function(event) {
5    console.log('Fibonacci result: ', event.data);
6};
7
8worker.postMessage(40); // Delegate heavy computation to the worker
  • הקוד הזה הוא דוגמה לשימוש ב-Web Worker להפרדה והרצה של משימות כבדות כמו חישובי סדרת פיבונאצי מהתהליך הראשי.

דוגמה לציון שם משימה

להלן דוגמה לשליחת וקבלת הודעות תוך ציון שם משימה.

 1// worker.js
 2self.onmessage = function(event) {
 3    switch (event.data.task) {
 4        case 'add':
 5            const result = event.data.a + event.data.b;
 6            self.postMessage({ task: 'result', value: result });
 7            break;
 8        default:
 9            self.postMessage({ task: 'error', message: 'Invalid Task' });
10    }
11};
 1// Main thread
 2const worker = new Worker('worker.js');
 3
 4worker.onmessage = function(event) {
 5    switch (event.data.task) {
 6        case 'result':
 7            console.log('Task result: ', event.data.value);
 8            break;
 9        case 'error':
10            console.error('Error: ', event.data.message);
11            break;
12    }
13};
14
15worker.postMessage({ task: 'add', a: 10, b: 20 });
  • הקוד הזה מדגים ניתוב עיבוד לפי שם המשימה (task) שבהודעה, כאשר ה-Web Worker מחזיר תוצאות חישוב או שגיאות לתהליך הראשי יחד עם שם המשימה.

הערות

בעת שימוש ב-Web Worker, חשוב לשים לב לנקודות הבאות.

  • אין גישה ל-DOM (Cannot Access DOM) ‏Web Worker לא יכול לשנות את ה-UI או לגשת ל-DOM. מניפולציות ב-DOM צריכות להתבצע בתהליך הראשי.
  • תקורת תקשורת (Communication Overhead) יש תקורה מסוימת בעת העברת נתונים בין התהליך הראשי ל-Web Worker. זה עשוי להשפיע על הביצועים, במיוחד בהחלפת כמויות גדולות של נתונים לעיתים קרובות.
  • מדיניות אותו מקור (Same-Origin Policy) סקריפטים של Web Worker כפופים למדיניות same-origin. לא ניתן לטעון סקריפטים מתחומים שונים.

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

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

YouTube Video