ข้อมูลเบื้องต้นของ Web Worker

ปัญหา: การเกิดขึ้นพร้อมกันของ JavaScript

มีปัญหาคอขวดจำนวนมากที่ขัดขวางไม่ให้ระบบย้ายแอปพลิเคชันที่น่าสนใจ (เช่น จากการติดตั้งใช้งานจำนวนมากของเซิร์ฟเวอร์) ไปยัง JavaScript ฝั่งไคลเอ็นต์ เช่น ความเข้ากันได้ของเบราว์เซอร์ การพิมพ์แบบคงที่ การช่วยเหลือพิเศษ และประสิทธิภาพ แต่ในทางกลับกัน ผู้ให้บริการเบราว์เซอร์ก็พัฒนาความเร็วของเครื่องมือ JavaScript ของตนได้อย่างรวดเร็ว

สิ่งหนึ่งที่ยังคงเป็นอุปสรรคสำหรับ JavaScript ก็คือตัวภาษาเอง JavaScript เป็นสภาพแวดล้อมแบบเทรดเดียว ซึ่งหมายความว่าสคริปต์หลายรายการจะทำงานพร้อมกันไม่ได้ ตัวอย่างเช่น สมมติว่ามีเว็บไซต์ที่ต้องจัดการเหตุการณ์ UI, ค้นหาและประมวลผลข้อมูล API จำนวนมาก และดัดแปลง DOM ค่อนข้างเหมือนกันใช่ไหม อย่างไรก็ตาม ทั้ง 2 อย่างนี้ไม่สามารถเกิดขึ้นพร้อมกันเนื่องจากข้อจำกัดในรันไทม์ JavaScript ของเบราว์เซอร์ การเรียกใช้สคริปต์จะเกิดขึ้นภายในเทรดเดียว

นักพัฒนาซอฟต์แวร์จะเลียนแบบ "การเกิดขึ้นพร้อมกัน" โดยใช้เทคนิคต่างๆ เช่น setTimeout(), setInterval(), XMLHttpRequest และเครื่องจัดการเหตุการณ์ ได้ ฟีเจอร์ทั้งหมดนี้ทำงานแบบไม่พร้อมกัน แต่การไม่บล็อกไม่ได้หมายถึงการเกิดขึ้นพร้อมกัน ระบบจะประมวลผลเหตุการณ์ที่ไม่พร้อมกันหลังจากแสดงผลสคริปต์ที่เรียกใช้ปัจจุบันแล้ว ข่าวดีก็คือ HTML5 ให้บางอย่างที่ดีกว่าการแฮ็กเหล่านี้!

ขอแนะนำ Web Workers: นำชุดข้อความไปยัง JavaScript

ข้อกำหนดของ Web Workers กำหนด API สำหรับการวางสคริปต์พื้นหลังในเว็บแอปพลิเคชันของคุณ Web Workers ให้คุณทำสิ่งต่างๆ ได้ เช่น เริ่มการทำงานของสคริปต์ที่ใช้เวลานานเพื่อจัดการงานที่เน้นการคำนวณ แต่ไม่บล็อก UI หรือสคริปต์อื่นๆ เพื่อจัดการการโต้ตอบของผู้ใช้ พวกเขาจะช่วยหยุดกล่องโต้ตอบ "สคริปต์ไม่ตอบสนอง" ที่น่ารังเกียจ ที่เราทุกคนชื่นชอบ:

กล่องโต้ตอบสคริปต์ไม่ตอบสนอง
กล่องโต้ตอบสคริปต์ที่ไม่ตอบสนองซึ่งพบบ่อย

ผู้ปฏิบัติงานใช้การส่งผ่านข้อความที่มีลักษณะคล้ายชุดข้อความเพื่อให้การทำงานพร้อมกัน ซึ่งเหมาะสำหรับการทำให้ UI รีเฟรช มีประสิทธิภาพ และตอบสนองผู้ใช้อยู่เสมอ

ประเภทของ Web Worker

โปรดทราบว่าข้อกำหนดได้กล่าวถึง Web Worker 2 ประเภท ได้แก่ Dedicated Worker และ Shared Workers บทความนี้จะกล่าวถึง ผู้ปฏิบัติงานเฉพาะทางเท่านั้น เราจะเรียกลูกค้าเหล่านี้ว่า "เว็บผู้ปฏิบัติงาน" หรือ "ผู้ปฏิบัติงาน"

เริ่มต้นใช้งาน

Web Worker จะทำงานในเทรดที่แยกต่างหาก ดังนั้น โค้ดที่เรียกใช้จะต้องอยู่ในไฟล์แยกต่างหาก แต่ก่อนที่จะดำเนินการดังกล่าว สิ่งแรกที่ต้องทำคือสร้างออบเจ็กต์ Worker ใหม่ในหน้าหลัก ตัวสร้างจะใช้ชื่อสคริปต์ผู้ปฏิบัติงาน:

var worker = new Worker('task.js');

หากมีไฟล์ที่ระบุ เบราว์เซอร์จะสร้างเทรดผู้ปฏิบัติงานใหม่ ซึ่งจะดาวน์โหลดแบบไม่พร้อมกัน ผู้ปฏิบัติงานจะไม่เริ่มทํางานจนกว่าไฟล์จะดาวน์โหลดและเรียกใช้เสร็จสมบูรณ์ หากเส้นทางไปยังผู้ปฏิบัติงานแสดงข้อผิดพลาด 404 ผู้ปฏิบัติงานจะล้มเหลวโดยไม่มีการแจ้งเตือน

หลังจากสร้างผู้ปฏิบัติงานแล้ว ให้เริ่มต้นโดยเรียกใช้เมธอด postMessage():

worker.postMessage(); // Start the worker.

การสื่อสารกับผู้ปฏิบัติงานผ่านทางข้อความ

การสื่อสารระหว่างงานและหน้าหลักจะดำเนินการโดยใช้โมเดลเหตุการณ์และเมธอด postMessage() postMessage() จะยอมรับสตริงหรือออบเจ็กต์ JSON เป็นอาร์กิวเมนต์เดียวก็ได้ ทั้งนี้ขึ้นอยู่กับเบราว์เซอร์/เวอร์ชัน เวอร์ชันล่าสุดของเบราว์เซอร์สมัยใหม่รองรับการส่งออบเจ็กต์ JSON

ด้านล่างนี้เป็นตัวอย่างการใช้สตริงเพื่อส่ง " Hello World" ไปยังผู้ปฏิบัติงานใน doWork.js ผู้ปฏิบัติงานจะส่งคืน ข้อความที่ส่งมาให้

สคริปต์หลัก:

var worker = new Worker('doWork.js');

worker.addEventListener('message', function(e) {
console.log('Worker said: ', e.data);
}, false);

worker.postMessage('Hello World'); // Send data to our worker.

doWork.js (ผู้ปฏิบัติงาน):

self.addEventListener('message', function(e) {
self.postMessage(e.data);
}, false);

เมื่อมีการเรียกใช้ postMessage() จากหน้าหลัก ผู้ปฏิบัติงานของเราจะจัดการข้อความนั้นโดยการกำหนดตัวแฮนเดิล onmessage สำหรับเหตุการณ์ message เพย์โหลดของข้อความ (ในกรณีนี้คือ "สวัสดีโลก") จะเข้าถึงได้ใน Event.data แม้ว่าตัวอย่างนี้จะไม่น่าตื่นเต้นมากนัก แต่ก็แสดงให้เห็นว่า postMessage() เป็นวิธีในการส่งข้อมูลกลับไปยังเทรดหลักด้วย สะดวก

ระบบจะไม่คัดลอกข้อความที่ส่งระหว่างหน้าหลักและผู้ปฏิบัติงาน เช่น ในตัวอย่างถัดไป คุณเข้าถึงคุณสมบัติ "msg" ของข้อความ JSON ได้จากทั้ง 2 ตำแหน่ง ดูเหมือนว่าออบเจ็กต์จะส่งผ่านไปยังผู้ปฏิบัติงานโดยตรง แม้ว่าวัตถุจะทำงานในพื้นที่เฉพาะที่แยกต่างหาก ในความเป็นจริง สิ่งที่เกิดขึ้นคือวัตถุกำลังถูกทำให้เป็นอนุกรมขณะส่งไปให้ผู้ปฏิบัติงาน แล้วก็ยกเลิกการซีเรียลที่อีกฝั่งหนึ่ง หน้าเว็บและผู้ปฏิบัติงานไม่ได้แชร์อินสแตนซ์เดียวกัน ดังนั้นผลลัพธ์สุดท้ายคือระบบจึงสร้างข้อมูลที่ซ้ำกันในแต่ละบัตรผ่าน เบราว์เซอร์ส่วนใหญ่ใช้ฟีเจอร์นี้โดยการเข้ารหัส/ถอดรหัส JSON โดยอัตโนมัติทั้ง 2 ฝั่ง

ต่อไปนี้เป็นตัวอย่างที่ซับซ้อนยิ่งขึ้นซึ่งส่งข้อความโดยใช้ออบเจ็กต์ JSON

สคริปต์หลัก:

<button onclick="sayHI()">Say HI</button>
<button onclick="unknownCmd()">Send unknown command</button>
<button onclick="stop()">Stop worker</button>
<output id="result"></output>

<script>
function sayHI() {
worker.postMessage({'cmd': 'start', 'msg': 'Hi'});
}

function stop() {
// worker.terminate() from this script would also stop the worker.
worker.postMessage({'cmd': 'stop', 'msg': 'Bye'});
}

function unknownCmd() {
worker.postMessage({'cmd': 'foobard', 'msg': '???'});
}

var worker = new Worker('doWork2.js');

worker.addEventListener('message', function(e) {
document.getElementById('result').textContent = e.data;
}, false);
</script>

doWork2.js:

self.addEventListener('message', function(e) {
var data = e.data;
switch (data.cmd) {
case 'start':
    self.postMessage('WORKER STARTED: ' + data.msg);
    break;
case 'stop':
    self.postMessage('WORKER STOPPED: ' + data.msg +
                    '. (buttons will no longer work)');
    self.close(); // Terminates the worker.
    break;
default:
    self.postMessage('Unknown command: ' + data.msg);
};
}, false);

ออบเจ็กต์ที่โอนได้

เบราว์เซอร์ส่วนใหญ่ใช้อัลกอริทึมการโคลนโครงสร้าง ซึ่งช่วยให้คุณส่งประเภทที่ซับซ้อนมากขึ้นเข้า/ออกจาก Worker เช่น File, Blob, ArrayBuffer และออบเจ็กต์ JSON อย่างไรก็ตาม เมื่อส่งข้อมูลประเภทเหล่านี้โดยใช้ postMessage() ระบบจะยังคงทำสำเนาไว้ ดังนั้น หากกำลังส่งไฟล์ขนาดใหญ่ 50 MB (เช่น) จะมีค่าใช้จ่ายที่เห็นได้ชัดในการรับไฟล์นั้นระหว่างผู้ปฏิบัติงานกับเทรดหลัก

การโคลนที่มีโครงสร้างนั้นเป็นเรื่องดี แต่การคัดลอกอาจใช้เวลาหลายร้อยมิลลิวินาที คุณใช้ออบเจ็กต์ที่โอนได้เพื่อต่อสู้กับการโจมตี Perf ได้

เมื่อใช้ออบเจ็กต์ที่โอนได้ ระบบจะโอนข้อมูลจากบริบทหนึ่งไปยังอีกบริบทหนึ่ง เอกสารนี้จะทำงานได้ไม่มีสำเนา ซึ่งช่วยปรับปรุงประสิทธิภาพในการส่งข้อมูลไปยังผู้ปฏิบัติงานได้เป็นอย่างมาก หากคุณมาจากกลุ่ม C/C++ ให้คิดว่านี่เป็นการอ้างอิง อย่างไรก็ตาม "เวอร์ชัน" จากบริบทการโทรจะใช้งานไม่ได้อีกต่อไปเมื่อโอนไปยังบริบทใหม่ ซึ่งต่างจากการอ้างอิงแบบอ้างอิง ตัวอย่างเช่น เมื่อโอน ArrayBuffer จากแอปหลักของคุณไปยัง Worker ระบบจะล้าง ArrayBuffer เดิมและจะใช้งานไม่ได้อีกต่อไป โดยระบบจะโอนเนื้อหาของไฟล์ไปยังบริบทของผู้ปฏิบัติงาน (โดยเงียบๆ)

หากต้องการใช้ออบเจ็กต์ที่โอนได้ ให้ใช้ลายเซ็นของ postMessage() ที่ต่างออกไปเล็กน้อย ดังนี้

worker.postMessage(arrayBuffer, [arrayBuffer]);
window.postMessage(arrayBuffer, targetOrigin, [arrayBuffer]);

กรณีของผู้ปฏิบัติงาน อาร์กิวเมนต์แรกคือข้อมูล และอาร์กิวเมนต์ที่ 2 คือลิสต์รายการที่ควรโอน อาร์กิวเมนต์แรกไม่จำเป็นต้องเป็น ArrayBuffer เช่น อาจเป็นออบเจ็กต์ JSON

worker.postMessage({data: int8View, moreData: anotherBuffer},
                [int8View.buffer, anotherBuffer]);

ประเด็นสําคัญ: อาร์กิวเมนต์ที่ 2 ต้องเป็นอาร์เรย์ของ ArrayBuffer นี่คือรายการรายการที่โอนได้ของคุณ

ดูข้อมูลเพิ่มเติมเกี่ยวกับการโอนได้ที่โพสต์ของเราที่ developer.chrome.com

สภาพแวดล้อมของผู้ปฏิบัติงาน

ขอบเขตของผู้ปฏิบัติงาน

ในบริบทของผู้ปฏิบัติงาน ทั้ง self และ this จะอ้างอิงขอบเขตรวมสำหรับผู้ปฏิบัติงาน ดังนั้น ตัวอย่างก่อนหน้านี้อาจเขียนเป็น

addEventListener('message', function(e) {
var data = e.data;
switch (data.cmd) {
case 'start':
    postMessage('WORKER STARTED: ' + data.msg);
    break;
case 'stop':
...
}, false);

หรือคุณสามารถตั้งค่าเครื่องจัดการเหตุการณ์ onmessage โดยตรง (แม้ว่านินจา JavaScript จะสนับสนุน addEventListener เสมอ)

onmessage = function(e) {
var data = e.data;
...
};

ฟีเจอร์ที่ผู้ปฏิบัติงานใช้ได้

เนื่องจากลักษณะการทำงานแบบมัลติเทรด Web Workers จึงมีสิทธิ์เข้าถึงฟีเจอร์ของ JavaScript เพียงบางส่วนเท่านั้น ดังนี้

  • ออบเจ็กต์ navigator
  • ออบเจ็กต์ location (อ่านอย่างเดียว)
  • XMLHttpRequest
  • setTimeout()/clearTimeout()และsetInterval()/clearInterval()
  • แคชของแอปพลิเคชัน
  • การนำเข้าสคริปต์ภายนอกโดยใช้เมธอด importScripts()
  • กำลังสร้าง Web Worker อื่นๆ

ผู้ปฏิบัติงานไม่มีสิทธิ์เข้าถึงสิ่งต่อไปนี้

  • DOM (ไม่ปลอดภัยต่อชุดข้อความ)
  • ออบเจ็กต์ window
  • ออบเจ็กต์ document
  • ออบเจ็กต์ parent

กำลังโหลดสคริปต์ภายนอก

คุณโหลดไฟล์สคริปต์ภายนอกหรือไลบรารีลงในผู้ปฏิบัติงานด้วยฟังก์ชัน importScripts() ได้ เมธอดนี้ไม่ใช้สตริงตั้งแต่ 0 สตริงขึ้นไปแทนชื่อไฟล์ของทรัพยากรที่จะนำเข้า

ตัวอย่างนี้โหลด script1.js และ script2.js ลงในผู้ปฏิบัติงาน

worker.js:

importScripts('script1.js');
importScripts('script2.js');

ซึ่งสามารถเขียนเป็นคำสั่งนำเข้ารายการเดียวก็ได้

importScripts('script1.js', 'script2.js');

ผู้ปฏิบัติงานย่อย

ผู้ปฏิบัติงานสามารถตั้งถิ่นฐานของผู้ปฏิบัติงานเด็กได้ เหมาะอย่างยิ่งสำหรับการแบ่งงาน ขนาดใหญ่ๆ ขณะรันไทม์ อย่างไรก็ตาม คนทำงานย่อยอาจมีข้อควรระวังบางประการดังนี้

  • ผู้ปฏิบัติงานย่อยต้องโฮสต์ภายในต้นทางเดียวกับหน้าหลัก
  • URI ภายในงานย่อยจะได้รับการแก้ไขโดยสัมพันธ์กับตำแหน่งของผู้ปฏิบัติงานหลัก (แทนที่จะเป็นหน้าหลัก)

โปรดทราบว่าเบราว์เซอร์ส่วนใหญ่สร้างกระบวนการแยกกันสำหรับผู้ปฏิบัติงานแต่ละคน ก่อนจะเริ่มสร้างฟาร์มคนงาน ให้ระวังการใช้ทรัพยากรระบบของผู้ใช้มากเกินไป เหตุผลหนึ่งก็คือระบบจะคัดลอก ข้อความที่ส่งต่อระหว่างหน้าหลักและผู้ปฏิบัติงานไว้โดยไม่แชร์ ดูการสื่อสารกับผู้ปฏิบัติงานผ่านการส่งข้อความ

ดูตัวอย่างวิธีสร้างผู้ปฏิบัติงานย่อยได้จากตัวอย่างในข้อกำหนด

ผู้ปฏิบัติงานในบรรทัด

ถ้าคุณต้องการสร้างสคริปต์สำหรับผู้ปฏิบัติงานทันที หรือสร้างหน้าเว็บที่ทำงานได้ด้วยตัวเอง โดยไม่ต้องสร้างไฟล์ผู้ปฏิบัติงานแยกต่างหาก เมื่อใช้ Blob() คุณจะ "แทรก" ผู้ปฏิบัติงานในหน้าในไฟล์ HTML เดียวกันกับตรรกะหลักได้โดยสร้างแฮนเดิล URL ให้โค้ดผู้ปฏิบัติงานเป็นสตริง ดังนี้

var blob = new Blob([
"onmessage = function(e) { postMessage('msg from worker'); }"]);

// Obtain a blob URL reference to our worker 'file'.
var blobURL = window.URL.createObjectURL(blob);

var worker = new Worker(blobURL);
worker.onmessage = function(e) {
// e.data == 'msg from worker'
};
worker.postMessage(); // Start the worker.

URL ของ Blob

สิ่งมหัศจรรย์มาพร้อมกับการโทรหา window.URL.createObjectURL() วิธีนี้จะสร้างสตริง URL แบบง่ายที่ใช้เพื่ออ้างอิงข้อมูลที่จัดเก็บไว้ในออบเจ็กต์ DOM File หรือ Blob ได้ เช่น

blob:http://localhost/c745ef73-ece9-46da-8f66-ebes574789b1

URL ของ Blob จะไม่ซ้ำกันและมีอายุการใช้งานของแอปพลิเคชัน (เช่น จนกว่า document จะถูกยกเลิกการโหลด) ถ้าคุณสร้าง URL ของ Blob จำนวนมาก คุณควรเผยแพร่การอ้างอิงที่ไม่จำเป็นอีกต่อไป คุณสามารถเผยแพร่ URL ของ Blob อย่างชัดแจ้งโดยส่งต่อไปยัง window.URL.revokeObjectURL():

window.URL.revokeObjectURL(blobURL);

ใน Chrome จะมีหน้าที่ดีสำหรับดู URL ของ Blob ที่สร้างขึ้นทั้งหมด: chrome://blob-internals/

ตัวอย่างแบบเต็ม

การดำเนินการเพิ่มเติมอีกขั้นทำให้เราเข้าใจวิธีแทรกโค้ด JS ของผู้ปฏิบัติงานในหน้าเว็บ เทคนิคนี้ใช้แท็ก <script> เพื่อกำหนดผู้ปฏิบัติงาน

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>

<div id="log"></div>

<script id="worker1" type="javascript/worker">
// This script won't be parsed by JS engines
// because its type is javascript/worker.
self.onmessage = function(e) {
    self.postMessage('msg from worker');
};
// Rest of your worker code goes here.
</script>

<script>
function log(msg) {
    // Use a fragment: browser will only render/reflow once.
    var fragment = document.createDocumentFragment();
    fragment.appendChild(document.createTextNode(msg));
    fragment.appendChild(document.createElement('br'));

    document.querySelector("#log").appendChild(fragment);
}

var blob = new Blob([document.querySelector('#worker1').textContent]);

var worker = new Worker(window.URL.createObjectURL(blob));
worker.onmessage = function(e) {
    log("Received: " + e.data);
}
worker.postMessage(); // Start the worker.
</script>
</body>
</html>

ในความคิดของผม วิธีการใหม่นี้ดูสะอาดตาขึ้นและอ่านออกได้ง่ายขึ้น ซึ่งจะกำหนดแท็กสคริปต์ด้วย id="worker1" และ type='javascript/worker' (ดังนั้นเบราว์เซอร์จึงไม่แยกวิเคราะห์ JS) ระบบจะแยกโค้ดดังกล่าวเป็นสตริงโดยใช้ document.querySelector('#worker1').textContent และส่งไปยัง Blob() เพื่อสร้างไฟล์

กำลังโหลดสคริปต์ภายนอก

เมื่อใช้เทคนิคเหล่านี้ในการแทรกโค้ดผู้ปฏิบัติงาน importScripts() จะทำงานก็ต่อเมื่อคุณระบุ URI สัมบูรณ์เท่านั้น หากคุณพยายามส่ง URI แบบสัมพัทธ์ เบราว์เซอร์จะร้องเรียนเกี่ยวกับข้อผิดพลาดด้านความปลอดภัย สาเหตุ: ผู้ปฏิบัติงาน (ตอนนี้สร้างขึ้นจาก BLOB URL) จะได้รับการแก้ไขด้วยคำนำหน้า blob: ในขณะที่แอปของคุณจะทำงานจากรูปแบบอื่น (น่าจะเป็น http://) ดังนั้น การดำเนินการไม่สำเร็จจึงเกิดจากข้อจำกัดแบบข้ามต้นทาง

วิธีหนึ่งในการใช้ importScripts() ในตัวผู้ปฏิบัติงานในหน้าคือการ "แทรก" URL ปัจจุบันของสคริปต์หลักที่เรียกใช้โดยส่ง URL ดังกล่าวไปยังผู้ปฏิบัติงานในหน้าและสร้าง URL ที่สมบูรณ์ด้วยตนเอง ซึ่งจะช่วยให้มั่นใจว่าระบบนำเข้าสคริปต์ภายนอกมาจากต้นทางเดียวกัน สมมติว่าแอปหลักของคุณทำงานจาก http://example.com/index.html:

...
<script id="worker2" type="javascript/worker">
self.onmessage = function(e) {
var data = e.data;

if (data.url) {
var url = data.url.href;
var index = url.indexOf('index.html');
if (index != -1) {
    url = url.substring(0, index);
}
importScripts(url + 'engine.js');
}
...
};
</script>
<script>
var worker = new Worker(window.URL.createObjectURL(bb.getBlob()));
worker.postMessage(<b>{url: document.location}</b>);
</script>

การจัดการข้อผิดพลาด

เช่นเดียวกับตรรกะ JavaScript คุณจะต้องจัดการข้อผิดพลาดใดๆ ที่มีในการทำงานของเว็บผู้ปฏิบัติงาน หากเกิดข้อผิดพลาดขณะที่ผู้ปฏิบัติงานกำลังดำเนินการ ErrorEvent จะเริ่มทำงาน อินเทอร์เฟซนี้มีพร็อพเพอร์ตี้ที่เป็นประโยชน์ 3 รายการในการระบุข้อผิดพลาด ได้แก่ filename ได้แก่ ชื่อสคริปต์ผู้ปฏิบัติงานที่ทำให้เกิดข้อผิดพลาด lineno คือหมายเลขบรรทัดที่เกิดข้อผิดพลาด และ message ซึ่งเป็นคำอธิบายข้อผิดพลาดที่สื่อความหมาย นี่คือตัวอย่างการตั้งค่าเครื่องจัดการเหตุการณ์ onerror เพื่อพิมพ์คุณสมบัติของข้อผิดพลาด

<output id="error" style="color: red;"></output>
<output id="result"></output>

<script>
function onError(e) {
document.getElementById('error').textContent = [
    'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message
].join('');
}

function onMsg(e) {
document.getElementById('result').textContent = e.data;
}

var worker = new Worker('workerWithError.js');
worker.addEventListener('message', onMsg, false);
worker.addEventListener('error', onError, false);
worker.postMessage(); // Start worker without a message.
</script>

ตัวอย่าง: WorkerWithError.js พยายามดำเนินการ 1/x โดยที่ไม่มีการกำหนด x

// สิ่งที่ต้องทำ: DevSite - ตัวอย่างโค้ดถูกนำออกเนื่องจากใช้เครื่องจัดการเหตุการณ์แบบอินไลน์

workerWithError.js:

self.addEventListener('message', function(e) {
postMessage(1/x); // Intentional error.
};

คำแนะนำเกี่ยวกับความปลอดภัย

ข้อจำกัดเกี่ยวกับการเข้าถึงในเครื่อง

เนื่องจากข้อจำกัดด้านความปลอดภัยของ Google Chrome ผู้ปฏิบัติงานจะไม่ทำงานเฉพาะที่ (เช่น จาก file://) ในเบราว์เซอร์เวอร์ชันล่าสุด แต่กลับล้มเหลวโดยไม่มีการแจ้งเตือน หากต้องการเรียกใช้แอปจากรูปแบบ file:// ให้เรียกใช้ Chrome ด้วยการตั้งค่าแฟล็ก --allow-file-access-from-files

เบราว์เซอร์อื่นมีข้อจำกัดเดียวกัน

การพิจารณาที่มาจากแหล่งเดียวกัน

สคริปต์ของผู้ปฏิบัติงานต้องเป็นไฟล์ภายนอกที่มีรูปแบบเหมือนกับหน้าการเรียกใช้ ดังนั้น คุณจึงโหลดสคริปต์จาก URL ของ data: หรือ URL javascript: ไม่ได้ และหน้า https: จะเริ่มสคริปต์สำหรับผู้ปฏิบัติงานที่ขึ้นต้นด้วย http: URL ไม่ได้

Use Case

แล้วแอปประเภทใดที่จะใช้ Web Worker แนวคิดเพิ่มเติมบางส่วนที่จะช่วยให้สมองของคุณทำงานมีดังนี้

  • การดึงข้อมูลล่วงหน้าและ/หรือการแคชข้อมูลไว้ใช้ในภายหลัง
  • การไฮไลต์ไวยากรณ์โค้ดหรือการจัดรูปแบบข้อความแบบเรียลไทม์อื่นๆ
  • โปรแกรมตรวจตัวสะกด
  • กำลังวิเคราะห์ข้อมูลวิดีโอหรือเสียง
  • I/O ในเบื้องหลังหรือการสำรวจบริการบนเว็บ
  • การประมวลผลอาร์เรย์ขนาดใหญ่หรือการตอบสนอง JSON ที่ตลกขบขัน
  • การกรองรูปภาพใน <canvas>
  • กำลังอัปเดตฐานข้อมูลเว็บในเครื่องหลายแถว

ดูข้อมูลเพิ่มเติมเกี่ยวกับกรณีการใช้งานที่เกี่ยวข้องกับ Web Workers API ได้ที่ภาพรวมผู้ปฏิบัติงาน

เดโม

รายการอ้างอิง