آموزش HTML - وب ورکرها API

ابزار HTML Web Workers API یکی از ویژگی‌های جاوااسکریپت است که برای اجرای محاسبات سنگین در پس‌زمینه و در یک نخ (Thread) مجزا استفاده می‌شود، بدون اینکه باعث اختلال در رابط کاربری شود.

در این فصل از Web Workers API، مباحث زیر را فرا خواهید گرفت:

  • وب ورکرها چیستند؟
  • نیاز به وب ورکرها
  • وب ورکرها چگونه کار می‌کنند؟
  • متوقف کردن وب ورکرها
  • مدیریت خطاهای وب ورکرها
  • پشتیبانی مرورگرها از وب ورکرها

وب ورکرها چیستند؟

  • ویژگی Web workers اجازه می‌دهد پردازش‌های طولانی بدون ایجاد وقفه اجرا شوند تا از هنگ کردن و پاسخگو نبودن صفحه جلوگیری شود.
  • Web workers اسکریپت‌های پس‌زمینه هستند و نسبتا سنگین محسوب می‌شوند، بنابراین نباید به تعداد زیاد استفاده شوند. برای مثال، راه‌اندازی یک ورکر مجزا برای هر پیکسل از یک تصویر چهار مگاپیکسلی کار مناسبی نیست.
  • وقتی یک اسکریپت داخل یک Web worker در حال اجراست، نمی‌تواند به شیء window صفحه وب (window.document) دسترسی داشته باشد.
  • Web workers دسترسی مستقیم به صفحه وب و DOM API ندارند. اگرچه Web workerها رابط کاربری مرورگر را قفل نمی‌کنند، اما همچنان می‌توانند منابع پردازنده (CPU) را مصرف کرده و سرعت کلی سیستم را کاهش دهند.

نیاز به وب ورکرها

جاوااسکریپت برای اجرا در یک محیط تک‌نخی (Single-threaded) طراحی شده است، به این معنی که چند اسکریپت نمی‌توانند به طور هم‌زمان اجرا شوند. موقعیتی را تصور کنید که در آن نیاز به مدیریت رویدادهای UI، دریافت و پردازش حجم زیادی از داده‌های API و تغییر در DOM دارید. در شرایطی که میزان استفاده از CPU بالا باشد، جاوااسکریپت باعث قفل شدن مرورگر شما خواهد شد.

مثال

بیایید یک مثال ساده را در نظر بگیریم که در آن جاوااسکریپت یک حلقه بزرگ را اجرا می‌کند. هنگام اجرای این کد، مرورگر شما از پاسخگویی باز می‌افتد:

<!DOCTYPE html>
<html>
<head>
   <title>Big for loop</title>
   <script>
      function bigLoop() {
         for (var i = 0; i <= 10000000000; i += 1) {
            var j = i;
         }
         alert("Completed " + j + "iterations");
      }
      function sayHello() {
         alert("Hello sir....");
      }
   </script>
</head>

<body>
   <input type="button" 
          onclick="bigLoop();" 
          value="Big Loop" />

   <input type="button" 
          onclick="sayHello();" 
          value="Say Hello" />
</body>
</html>

موقعیت توضیح داده شده در بالا را می‌توان با استفاده از Web Workers مدیریت کرد که تمام محاسبات سنگین را بدون ایجاد اختلال در رابط کاربری انجام می‌دهند و معمولاً روی نخ‌های جداگانه اجرا می‌شوند.

وب ورکرها چگونه کار می‌کنند؟

وب ورکرها با آدرس (URL) یک فایل جاوااسکریپت راه‌اندازی می‌شوند که حاوی کدهای اجرایی ورکر است. این کد شنوندگان رویداد (Event Listeners) را تنظیم کرده و با اسکریپت اصلی که آن را ساخته است ارتباط برقرار می‌کند. سنتکس ساده آن به شکل زیر است:

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

اگر فایل جاوااسکریپت مشخص‌شده وجود داشته باشد، مرورگر یک نخ ورکر جدید ایجاد می‌کند که به صورت ناهمگام (Asynchronously) دانلود می‌شود. اگر مسیر ورکر با خطای 404 مواجه شود، ورکر بدون نمایش خطا متوقف می‌شود.

اگر برنامه ما چند فایل جاوااسکریپت پشتیبان داشته باشد، می‌توانیم آن‌ها را با استفاده از متد importScripts() وارد کنیم که نام فایل‌ها را به عنوان آرگومان با کاما از هم جدا می‌کند:

importScripts("helper.js", "anotherHelper.js");

پس از ایجاد Web Worker، ارتباط بین وب ورکر و صفحه اصلی از طریق متد postMessage() انجام می‌شود. بسته به مرورگر و نسخه آن، متد postMessage() می‌تواند یک رشته یا یک شیء JSON را به عنوان تنها آرگومان خود بپذیرد.

پیام ارسال‌شده توسط Web Worker با استفاده از رویداد onmessage در صفحه اصلی قابل دسترسی است. در ادامه کد صفحه اصلی (hello.htm) قرار دارد که یک وب ورکر ایجاد می‌کند تا حلقه را اجرا کرده و مقدار نهایی متغیر j را بازگرداند:

مثال

<!DOCTYPE html>
<html>
<head>
   <title>Big for loop</title>
   <script>
      var worker = new Worker('bigLoop.js');
      worker.onmessage = function(event) {
         alert("Completed " + event.data + "iterations");
      };
      function sayHello() {
         alert("Hello sir....");
      }
   </script>
</head>

<body>
   <input type="button" 
          onclick="sayHello();" 
          value="Say Hello" />
</body>
</html>

در ادامه محتوای فایل bigLoop.js آمده است. این فایل از API مربوط به postMessage() برای ارسال اطلاعات به صفحه اصلی استفاده می‌کند:

for (var i = 0; i <= 1000000000; i += 1){
   var j = i;
}
postMessage(j);

متغیر j از فایل bigLoop.js با استفاده از تابع `postMessage()` ارسال می‌شود، که سپس در hello.htm از طریق ویژگی رویدادی `worker.onmessage = function(event) {}` دریافت می‌گردد.

متوقف کردن وب ورکرها

وب ورکرها به خودی خود متوقف نمی‌شوند، اما صفحه‌ای که آن‌ها را اجرا کرده است می‌تواند با فراخوانی متد terminate() آن‌ها را متوقف کند.

worker.terminate();

یک Web Worker متوقف‌شده دیگر به پیام‌ها پاسخ نمی‌دهد و هیچ محاسبه دیگری انجام نخواهد داد. ما نمی‌توانیم یک ورکر را دوباره راه‌اندازی کنیم؛ در عوض باید با استفاده از همان URL یک ورکر جدید بسازیم.

مدیریت خطاهای وب ورکرها

شما می‌توانید خطاهایی را که در Web Worker رخ می‌دهند، از طریق نخ اصلی و با استفاده از متد worker.onerror() مدیریت کنید.

مثال

کد زیر نمونه‌ای از تابع مدیریت خطا را در فایل جاوااسکریپت Web Worker نشان می‌دهد که خطاها را در کنسول ثبت می‌کند. با افزودن کد مدیریت خطا، مثال قبلی به شکل زیر تغییر خواهد کرد:

<!DOCTYPE html>
<html>
<head>
   <title>Big for loop</title>
   <script>
      var worker = new Worker('bigLoop.js');
      worker.onmessage = function(event) {
         alert("Completed " + event.data + "iterations");
      };
      worker.onerror = function(event) {
         console.log(event.message, event);
      };
      function sayHello() {
         alert("Hello sir....");
      }
   </script>
</head>

<body>
   <input type="button" 
          onclick="sayHello();" 
          value="Say Hello" />
</body>
</html>

می‌توانید از قطعه‌کد زیر به عنوان مدیر خطا (Error Handler) برای ورکر در صفحه اصلی استفاده کنید:

worker.onerror = function(event) {
   console.error("Error in web worker: " + event.message, event);
   alert("Error occurred in the web worker.");
   // Prevents the default handling of the error
   event.preventDefault(); 
};

بررسی پشتیبانی مرورگر

برای بررسی پشتیبانی مرورگر از Web Workers، می‌توانید از تست ویژگی webworkers در کتابخانه Modernizr استفاده کنید.

مثال

در ادامه سنتکس تشخیص پشتیبانی از ویژگی Web Worker در یک مرورگر آمده است:

<!DOCTYPE html>
<html>
<head>
   <title>Big for loop</title>
   <script src="/js/modernizr-1.5.min.js">
   </script>

   <script>
      if (Modernizr.webworkers) {
         alert("You have web workers support.");
      } else {
         alert("You do not have web workers support.");
      }
   </script>
</head>

<body>
   <p>
      Checking for Browser Support for web workers
   </p>
</body>
</html>

پیشرفت مطالعه: وضعیت خوانده‌شدن این درس فقط در همین مرورگر ذخیره می‌شود؛ بدون نیاز به حساب کاربری.