امروزه استفاده از صفحات وب، در همه امور به خوبی به
چشم میخورد و تاثیر این فناوری را میتوان در تمام عرصههای تولید و
استفاده از نرم افزار دید. web worker یکی از فناوریهای تحت وب بوده که
توسط W3C ارائه شده است. وب ورکر به شما اجازه میدهد تا بتوانید عملیاتی را
که نیاز به زمان زیادی برای پردازش دارد، در پشت صحنه انجام دهید؛ بدون
اینکه وقفهای در پردازش UI ایجاد شود. وب ورکر حتی به شما اجازه میدهد
چند thread را همزمان اجرا کنید و پردازشهایی موازی یکدیگر داشته باشید. از
آنجا که وب ورکرها یک ترد پردازشی جدا از UI به حساب میآیند، شما دسترسی
به DOM ندارید؛ ولی میتوانید از طریق ارسال پیام، با صفحه وب تعامل داشته
باشد.
قبل از استفاده از وب ورکر، بهتر هست مرورگر را بررسی کنیم که آیا از این قابلیت پشتیبانی میکند یا خیر؟ روش بررسی کردن این قابلیت، شیوههای مختلفی دارد که به تعدادی از آنها اشاره میکنیم:
هر کدام از عبارات بالا را اگر در شرطی بگذارید و جواب true بازگردانند به معنی پشتیبانی مرورگر این ویژگی است. modernizr فریمورکی جهت بررسی قابلیتهای موجود در مرورگر است.
نحوه پشتیبانی وب ورکرها در مروگرهای مختلف به شرح زیر است:
سپس در فایل HTML به شکل زیر وب ورکر را مورد استفاده قرار میدهیم. در سازنده Worker، ما آدرس فایل js را وارد میکنیم و برای توقف آن نیز از متد terminate استفاده میکنیم:
در صورتی که خطایی در ورکر رخ بدهد، میتوانید از طریق متد onerror آن را دریافت کنید:
مقدار برگشتی event شامل اطلاعات زیادی در مورد خطاست که شامل نام و مسیر
فایل خطا، شماره خط و شماره ستون خطا، پیام خطا و ... میشود.
همچنین برای ورکر هم میتوانید پیامی را ارسال کنید، برای همین کد زیر را به کد ورکر اضافه میکنیم:
و در صفحه HTML هم کد دریافت پیام از ورکر را به شکل زیر تغییر میدهیم:
در این حالت اگر عدد به هشت برسد، ما به ورکر میگوییم که عدد را به صد تغییر بده.
روشهای ارسال پیام
به این نوع ارسال پیام، Structure Cloning گویند و با استفاده از این شیوه، امکان ارسال نوعهای مختلفی امکان پذیر شده است؛ مثل فایلها، Blobها، آرایهها و کلاسها و ... ولی باید دقت داشته باشید که این ارسال پیامها به صورت کپی بوده و آدرسی ارجاع داده نمیشود و باید مدنظر داشته باشید که ارسال یک فایل، به فرض پنجاه مگابایتی، به خوبی قابل تشخیص است. طبق نظر گوگل، از حجم 32 مگابایت به بعد، این گفته به خوبی مشهود بوده و زمانبر میشود. به همین علت فناوری با نام Transferable Objects ایجاد شده است که "کپی صفر" Zero-Copy را پیاده سازی میکند و باعث بهبود عملگر کپی میشود:
پارامتر اول آن، آرایه بافر شده است و دومی هم لیست آیتمهایی است که قرار است انتقال یابند:
یا ارسال اطلاعات بیشتر:
در صورتیکه بتواند انتقال را انجام بدهد، byteLength حجم اطلاعات ارسالی را
بر میگرداند؛ در غیر اینصورت عدد 0 را به عنوان خروجی بر میگرداند. در این پرسش و پاسخ میتوانید نمونه یک انتقال و دریافت را در این روش، ببینید.
نمودار زیر مقایسهای بین Structure Cloning و Transferable Objects است که توسط گوگل منتشر شده است:
که البته به طور خلاصهتری نیز میتوان نوشت:
Inline Worker
اگر بخواهید در همان صفحه اصلی یک ورکر را ایجاد کنید و فایل جاوا اسکریپتی خارجی نداشته باشید، میتوانید از inline worker استفاده کنید. در این روش باید یک نوع blob را ایجاد کنید:
کاری که متد حیرت
انگیز createObjectURL انجام میدهد این است که از دادههای ذخیره شده در یک
blob یا نوع فایل، یک آدرس ارجاعی شبیه آدرس زیر را ایجاد میکند:
آدرسهایی که این متد تولید میکند، یکتا بوده و تا پایان عمر صفحه، اعتبار
دارند. به همین دلیل هر موقع به آنها نیاز نداشتید، از دست آنها خلاص شوید،
تا حافظه به هدر نرود. برای آزادسازی حافظه میتوان دستور زیر را به کار
برد:
مرورگر کروم با دستور زیر به شما اجازه میدهد همه آدرسهای blobها را ببینید:
قبل از استفاده از وب ورکر، بهتر هست مرورگر را بررسی کنیم که آیا از این قابلیت پشتیبانی میکند یا خیر؟ روش بررسی کردن این قابلیت، شیوههای مختلفی دارد که به تعدادی از آنها اشاره میکنیم:
typeof(Worker) !== "undefined"
<script src="/js/modernizr-1.5.min.js"></script> Modernizr.webworkers
نحوه پشتیبانی وب ورکرها در مروگرهای مختلف به شرح زیر است:
برای ایجاد یک وب ورکر ابتدا لازم است تا کدهای پردازشی را داخل یک فایل js جداگانه بنویسیم. در این مثال ما قصد داریم که شمارندهای را بنویسیم:
var i=0; function timedCount() { i=i+1; postMessage(i); setTimeout("timedCount()", 500); } timedCount();
سپس در فایل HTML به شکل زیر وب ورکر را مورد استفاده قرار میدهیم. در سازنده Worker، ما آدرس فایل js را وارد میکنیم و برای توقف آن نیز از متد terminate استفاده میکنیم:
<!DOCTYPE html> <html> <head> <script> var worker; function Start() { worker=new Worker("webwroker-even-numbers.js"); worker.onmessage=(event)=> { document.getElementById("output").value=event.data; } } function Stop() { worker.terminate(); } </script> <meta charset="utf-8"> <title></title> </head> <body> <input type="text" id="output"/> <button onclick="Start();">Start Worker</button> <button onclick="Stop();">Stop Worker</button> </body> </html>
worker.onerror = function (event) { console.log(event.message, event); };
همچنین برای ورکر هم میتوانید پیامی را ارسال کنید، برای همین کد زیر را به کد ورکر اضافه میکنیم:
self.onmessage=(event)=>{ i=event.data; };
worker.onmessage=(event)=> { document.getElementById("output").value=event.data; if(event.data==8) worker.postMessage(100); }
روشهای ارسال پیام
به این نوع ارسال پیام، Structure Cloning گویند و با استفاده از این شیوه، امکان ارسال نوعهای مختلفی امکان پذیر شده است؛ مثل فایلها، Blobها، آرایهها و کلاسها و ... ولی باید دقت داشته باشید که این ارسال پیامها به صورت کپی بوده و آدرسی ارجاع داده نمیشود و باید مدنظر داشته باشید که ارسال یک فایل، به فرض پنجاه مگابایتی، به خوبی قابل تشخیص است. طبق نظر گوگل، از حجم 32 مگابایت به بعد، این گفته به خوبی مشهود بوده و زمانبر میشود. به همین علت فناوری با نام Transferable Objects ایجاد شده است که "کپی صفر" Zero-Copy را پیاده سازی میکند و باعث بهبود عملگر کپی میشود:
worker.postMessage(arrayBuffer, [arrayBuffer]);
var ab = new ArrayBuffer(1); worker.postMessage(ab, [ab]); if (ab.byteLength) { alert('Transferables are not supported in your browser!'); } else { // Transferables are supported. }
worker.postMessage({data: ab1, moreData: ab2}, [ab1, ab2]);
نمودار زیر مقایسهای بین Structure Cloning و Transferable Objects است که توسط گوگل منتشر شده است:
RTT=Round Trip Time
نمودار
بالا برای یک فایل 32 مگابایتی است که زمان رفت به ورکر و پاسخ (برگشت از ورکر)
را اندازه گرفتهاند. در ستونهای اول، این موضوع برای فایرفاکس به روش
Structure Cloning به مدت 302 میلی ثانیه زمان برد که همین موضوع برای
Transferables حدود 6.6 میلی ثانیه زمان برد.
آقای اریک بایدلمن در بخش مهندسی کروم گوگل میگوید: همین سرعت به ما در انتقال تکسچرها و مشها در WebGL کمک میکند.
استفاده از اسکریپت خارجی
در صورتیکه قصد دارید از یک اسکرپیت خارجی، در ورکر استفاده کنید، تابع importScripts برای اینکار ایجاد شده است:
importScripts('script1.js'); importScripts('script2.js');
importScripts('script1.js', 'script2.js');
Inline Worker
اگر بخواهید در همان صفحه اصلی یک ورکر را ایجاد کنید و فایل جاوا اسکریپتی خارجی نداشته باشید، میتوانید از inline worker استفاده کنید. در این روش باید یک نوع blob را ایجاد کنید:
var blob = new Blob([ "onmessage = function(e) { postMessage('msg from worker'); }"]); // یک آدرس همانند آدرس ارجاع به فایل درست میکند var blobURL = window.URL.createObjectURL(blob); var worker = new Worker(blobURL); worker.onmessage = function(e) { // e.data... }; worker.postMessage(); // ورکر آغاز میشود
blob:http://localhost/c745ef73-ece9-46da-8f66-ebes574789b1
window.URL.revokeObjectURL(blobURL);
chrome://blob-internals