JavaScript Web Workers

วันนี้ได้ mail จากลูกค้าเจ้านึง เขียนประมาณว่า “กูอยากใช้ Shared Web Workers (SWW) มึงช่วยทำไงก็ได้ให้ JavaScript API มึง support SWW ที หรือไม่งั้นมึงบอก design, protocol มา เดี๋ยวกูเขียน API ใหม่เอง (แต่มึงต้อง test, fix bug แล้ว support code ที่กูเขียนนะ – สัด)” ผมก็เลยต้องมานั่งหาว่าไอ้ Web Workers หรือ Shared Web Worker มันคือะไร เพราะไม่เคยได้ยินมาก่อน entry นี้จะเขียนถึง Web Workers ก่อนละกัน

Web Workers (Web Workers @Wikipedia) เป็น feature ของ HTML 5 ที่ทำให้สามารถรัน JavaScript แบบ multithread ได้ครับ

คือปกติ JavaScript มันเป็น single thread มันจะรันคำสั่งตาม queue ของมันเสมอ ไม่ว่าจะเป็นการ display, validate, ต่อ ajax, websocket หรือทำ function ต่างๆ ที่เราเขียน ทุกอย่างอยู่บน thread เดียวกันหมด ดังนั้นเวลามี function อะไรใน queue รันหนักๆ มันจะกระทบให้ทั้ง page ช้าไปหมดจนบางที browser จะขึ้น pop up มาถามว่า page กำลัง script อะไรบางอย่างทำให้มันช้าจน freeze นะ จะ kill page นี้ทิ้งไหม

เขาก็เลยคิด Web Workers ขึ้นมาเพื่อแตกงานอะไรที่หนักๆ ไปอีก thread นึงเลย จากที่ค้นๆ มาเขาจะยกตัวอย่างเป็นคำนวนค่า Pi ที่ต้องวน loop หนักๆ หรืออะไรที่ต้องคุยกับ server เยอะๆ แยกเป็น thread worker ไปแล้วให้ thread หลักรับผลการทำงานจาก thread ลูก (Worker) แบบ asynchronous ไปซะ

Concept หลักๆ ของการเขียน Web Workers คือ

ตัวแม่ (ชื่อ main.html ละกัน)

//new Worker object
var wk=new Worker("worker.js");
//ใช้ addEventListener เพื่อรับ message จาก Woker --> self.postMessage('worker got : '+data);
wk.addEventListener("message",function(oEvent){
	document.getElementById('display').textContent = oEvent.data;
	//จะ print 'worker got : Hello'
},false);

//start Worker และส่ง message ให้ Worker ด้วย postMessage
wk.postMessage('Hello'); 

worker.js

//ใช้ addEventListener เพื่อรับ message จาก Main --> wk.postMessage('Hello'); 
self.addEventListener('message',function(e){
	var data=e.data;
	//ใช้ postMessage เพื่อส่งกลับให้ Main
	self.postMessage('worker got : '+data);
},false); 


จะเห็นได้ว่า Worker และ Main คุยกันด้วย addEventListener และ postMessage ครับ โดย addEventListener ใช้รับ data (event.data) จาก postMessage อย่างเดียว ส่วน postMessage ก็จะใช้ส่ง data ให้ addEventListener อย่างเดียวเช่นกัน (งงม่ะ)

เรามาดูตัวอย่างการใช้งานที่ผมเขียนขึ้นมาเป็น example ตอนเอาไปคุยกับ Dev ละกันครับ เป็น code ง่ายๆ ที่ยิง XMLHttpRequest ไปขอ data แบบ JSON

snapshot_worker.html

var quote_url="http://localhost:8080/quote.aspx";
var quote_data={
	'item':['GOOG'],
	'filter':['BID','ASK'],
};

window.onload=function(){
	//new Worker obj
	var snapshot=new Worker("./snapshot_worker.js");
	//addEventListner อันนี้ใช้รับ JSON ที่ Worker.postMessage ส่งมา
	snapshot.addEventListener("message",function(oEvent){
		document.getElementById('display').textContent = JSON.stringify(oEvent.data);
	},false);

	//ส่ง url กับ payload ให้ Worker
	snapshot.postMessage({
		url:chart_url,
		request_data:quote_data
	}); 
};
<body>
	<div id="display"></div>
</body>

snapshot_worker.js

//ยิง Ajax ไปหา server เพื่อขอข้อมูลครับ
var request=function(url,request_data){
	var req=new XMLHttpRequest();
	
	req.open("POST",url,true);
	req.setRequestHeader("Content-type","application/json");
	req.onreadystatechange=function(){
		if(req.readyState===4){
			if(req.status===200){
				//ส่ง JSON response จาก server ให้ addEventListner ของ snapshot_worker.html
				self.postMessage(req.responseText);
			}else{
				self.postMessage('Error');
			}
		}
	};
	req.send(JSON.stringify(request_data));
};
//addEventListner อันนี้ใช้รับ url กับ payload ที่ snapshot_worker.html postMessage ส่งมา
self.addEventListener('message',function(e){
	var data=e.data;
	request(data.url,data.request_data);
	self.postMessage('sending request url');

},false);

Feature นี้ตอนนี้มี IE 10, Chrome และ Firefox ที่ Support ครับ ซึ่งเท่าที่รู้ลูกค้าเจ้าที่ขอนี่จะเน้น IE 7, IE 8 และ IE 9 เป็นหลัก ก็ไม่รู้ว่าแม่มจะขอมาทำเห้อะไรเหมือนกัน -*-

ข้อเสียของ Web Workers เท่าที่อ่านและเจอมาคือตัว Workers จะ access DOM อะไรไม่ได้เลย, console.log ไม่ได้, alert ไม่ได้ และพวก Dev Tool ทั้งหลาย debug ไม่ได้ครับ (แม้จะเห็น code และใส่ break point ไปก็ตาม) เรียกได้ว่าถ้าพังทีนี่งงกันฉิบหายเลยครับ

อ้อ เวบที่ผมคิดว่าเจ๋งมากๆ อธิบาย Web Worker ได้ดี อ่านง่ายคือ Introducing HTML 5 Web Workers: Bringing Multi-threading to JavaScript @http://www.htmlgoodies.com โดยคุณ Robert Gravelle ครับ

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.