HTML5 รองรับ APIs เช่น Web Worker ช่วยให้เว็บเพจสามารถเรียกใช้รหัสมัลติเธรดในสถานการณ์ที่ปลอดภัย อย่างไรก็ตามผู้ปฏิบัติงานบนเว็บนั้นอยู่ภายใต้ข้อ จำกัด หลายประการเนื่องจากไม่สามารถแบ่งปันข้อมูลหน่วยความจำได้อย่างแท้จริงและสามารถใช้ข้อความเพื่อแจ้งสถานะได้ดังนั้นจึงไม่สามารถเรียกได้ว่า "มัลติเธรด" ในความหมายที่แท้จริง
อินเทอร์เฟซของ Web Worker นั้นไม่สะดวกมากที่จะใช้ โดยทั่วไปมาพร้อมกับ Sandbox ซึ่งเรียกใช้ไฟล์ JS อิสระใน Sandbox และสื่อสารกับเธรดหลักผ่าน postmessage และ OnMessge:
การคัดลอกรหัสมีดังนี้:
var worker = คนงานใหม่ ("my.js");
var bundle = {message: 'hello world', id: 1};
Worker.postMessage (Bundle); // postmessage สามารถผ่านวัตถุที่เป็นอนุกรมได้ในอดีต
Worker.onMessage = function (evt) {
console.log (evt.data); // เปรียบเทียบวัตถุที่ส่งผ่านในคนงานด้วยวัตถุในเธรดหลัก
console.log (มัด); // {ข้อความ: 'Hello World', id: 1}
-
การคัดลอกรหัสมีดังนี้:
// ใน my.js
onMessage = function (evt) {
var data = evt.data;
data.id ++;
postmessage (ข้อมูล); // {ข้อความ: 'Hello World', id: 2}
-
ผลลัพธ์อาจพบได้ว่า ID ของข้อมูลที่ได้รับในเธรดเพิ่มขึ้น แต่หลังจากผ่านไปแล้ว ID ในชุดของเธรดหลักจะไม่เปลี่ยนแปลง ดังนั้นวัตถุที่ส่งผ่านในเธรดจะถูกคัดลอกจริง ด้วยวิธีนี้เธรดจะไม่แบ่งปันข้อมูลหลีกเลี่ยงการอ่านและเขียนความขัดแย้งดังนั้นจึงปลอดภัย ค่าใช้จ่ายในการรับรองความปลอดภัยของเธรดคือการจำกัดความสามารถในการใช้งานวัตถุเธรดหลักในเธรด
กลไกมัลติเธรดที่ จำกัด ดังกล่าวไม่สะดวกในการใช้งาน แน่นอนเราหวังว่าคนงานสามารถสนับสนุนความสามารถในการทำให้รหัสดูเหมือนว่าจะทำงานมัลติเธรดในเวลาเดียวกัน ตัวอย่างเช่นรหัสสนับสนุนที่มีลักษณะดังต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
VAR Worker = ใหม่เธรด Workerer (Bundle /*แบ่งปัน OBJ* /);
Worker.run (ฟังก์ชั่น (Bundle) {
// ทำ sth ในเธรดคนงาน ...
this.runonuithread (ฟังก์ชั่น (bundle /*ที่แชร์ obj* /) {
// ทำ sth ในกระทู้ UI หลัก ...
-
-
-
ในรหัสนี้หลังจากที่เราเริ่มงานเราสามารถปล่อยให้รหัสใด ๆ ทำงานในคนงานและเมื่อเราต้องการใช้งานเธรด UI (เช่นการอ่านและการเขียน DOM) เราสามารถกลับไปที่เธรดหลักเพื่อดำเนินการผ่านนี้ runonuithread
แล้วจะใช้กลไกนี้อย่างไร? ดูรหัสต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
Function WorkerThread (ShareDobj) {
this._worker = คนงานใหม่ ("thread.js");
this._completes = {};
this._task_id = 0;
this.sharedobj = Sharedobj;
var self = this;
this._worker.onMessage = function (evt) {
var ret = evt.data;
ถ้า (ret .__ ui_task __) {
// ทำงานกับงาน UI
var fn = (ฟังก์ชั่นใหม่ ("return"+ret .__ ui_task __)) ();
fn (ret.sharedobj);
}อื่น{
self.sharedobj = ret.sharedobj;
self._completes [ret.taskid] (ret);
-
-
-
workerThread.prototype.run = function (งานเสร็จสมบูรณ์) {
var _task = {__thread_task __: task.toString (), sharedobj: this.sharedobj, taskId: this._task_id};
this._completes [this._task_id ++] = เสร็จสมบูรณ์;
this._worker.postMessage (_task);
-
รหัสด้านบนกำหนดวัตถุเธรด วัตถุนี้สร้างเว็บผู้ทำงานที่กำลังใช้เธรด. js บันทึกวัตถุที่ใช้ร่วมกัน Sharedobj และประมวลผลข้อความที่ส่งกลับโดยเธรด. js
หากข้อความ UI_TASK ถูกส่งกลับใน Thread.js ให้เรียกใช้ฟังก์ชั่นที่ส่งผ่านโดยข้อความนี้ มิฉะนั้นเรียกใช้การโทรกลับที่สมบูรณ์ของการรันมาดูกันว่า thread.js เขียนอย่างไร:
การคัดลอกรหัสมีดังนี้:
onMessage = function (evt) {
var data = evt.data;
if (data && data .__ thread_task __) {
task var = data .__ thread_task__;
พยายาม{
var fn = (ฟังก์ชั่นใหม่ ("return"+task)) ();
var ctx = {
Threadsignal: จริง
การนอนหลับ: ฟังก์ชั่น (ช่วงเวลา) {
ctx.threadsignal = false;
settimeout (_run, Interval);
-
runonuithRead: ฟังก์ชัน (งาน) {
postmessage ({__ ui_task __: task.toString (), sharedobj: data.sharedobj});
-
-
ฟังก์ชั่น _run () {
ctx.threadsignal = true;
var ret = fn.call (ctx, data.sharedobj);
postmessage ({ข้อผิดพลาด: null, returnValue: ret, __thread_task __: งาน, sharedobj: data.sharedobj, taskId: data.taskid});
-
_run (0);
} catch (ex) {
postmessage ({ข้อผิดพลาด: ex.toString (), returnValue: null, sharedobj: data.sharedobj});
-
-
-
จะเห็นได้ว่า thread.js ได้รับข้อความจากเธรด UI ซึ่งสำคัญที่สุดคือ Thread_task ซึ่งเป็น "งาน" ที่ผ่านโดยเธรด UI ที่ต้องดำเนินการโดยเธรดคนงาน เนื่องจากฟังก์ชั่นไม่สามารถเป็นอนุกรมได้จึงผ่านสตริง เธรดคนงานจะวิเคราะห์สตริงลงในฟังก์ชันเพื่อดำเนินการงานที่ส่งโดยเธรดหลัก (โปรดทราบว่า object sharedobj จะถูกส่งผ่านในงาน) หลังจากการดำเนินการเสร็จสิ้นผลการส่งคืนจะถูกส่งผ่านไปยังเธรด UI ผ่านข้อความ ลองดูที่วัตถุที่แชร์ Sharedobj อย่างใกล้ชิดยิ่งขึ้นนอกเหนือจากค่าส่งคืนผลตอบแทน เมื่อผ่านไปเนื่องจากเธรดคนงานและเธรด UI ไม่แชร์วัตถุเราจะซิงโครไนซ์วัตถุทั้งสองด้านผ่านการกำหนด (กระทู้นี้ปลอดภัยหรือไม่ทำไม?)
คุณจะเห็นว่ากระบวนการทั้งหมดไม่ซับซ้อน หลังจากการใช้งานนี้เธรดนี้สามารถใช้งานได้สองครั้งต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
var t1 = ใหม่ workerThread ({i: 100} /*แบ่งปัน obj* /);
setInterval (function () {
t1.run (ฟังก์ชั่น (sharedobj) {
ส่งคืน Sharedobj.i ++;
-
ฟังก์ชั่น (r) {
console.log ("t1>" + r.returnvalue + ":" + r.error);
-
-
}, 500);
var t2 = new WorkerThread ({i: 50});
t2.run (ฟังก์ชั่น (sharedobj) {
ในขณะที่ (this.threadsignal) {
Sharedobj.i ++;
this.runonuithread (ฟังก์ชั่น (sharedobj) {
w ("body ul"). ภาคผนวก ("<li>"+sharedobj.i+"</li>");
-
this.sleep (500);
-
ส่งคืน Sharedobj.i;
}, ฟังก์ชัน (r) {
console.log ("t2>" + r.returnvalue + ":" + r.error);
-
การใช้งานนี้ให้โครงสร้างที่ดีความยืดหยุ่นและการบำรุงรักษาที่ดีทั้งในรูปแบบและข้อกำหนดทางความหมาย
โอเคนั่นคือทั้งหมดสำหรับการอภิปรายเกี่ยวกับการใช้งานของผู้ปฏิบัติงานบนเว็บ นักเรียนที่สนใจสามารถดูโครงการนี้: https://github.com/akira-cn/workerthread.js (เนื่องจากผู้ปฏิบัติงานต้องใช้การทดสอบเซิร์ฟเวอร์ฉันใส่ copycat httpd.js เป็นพิเศษในโครงการซึ่งเป็นบริการ HTTP ที่ง่ายมาก