news

Service Worker (سرویس ورکر) چیست؟

برای توضیح سرویس ورکر ابتدا باید ذهنتان را با چند مطلب دیگر آشنا کنیم. زبان جاوا اسکریپت در زمان اجرا، یک زبان single thread است، به این معنی که به مانند یک کلاف نخ برای رسیدن به قسمت خاصی از دستورات، مفسر برنامه باید تمام مسیر قبل از آن را پیموده باشد. این بدان معنی است که برعکس زبان های برنامه نویسی Multi thread مانند پایتون، C++، جاوا و … که همزمان می توانند چند بخش از دستورات را بدون نیاز به پایان دادن بخش قبلی به اجرا در بیاورند، جاوا اسکریپت تنها قادر است که در هر زمان مشخص فقط یک بخش را به اجرا دربیاورد و برای رفتن به بخش بعدی، ضروری ست که بخش، تابع یا خط کد فعلی به پایان خود رسیده باشد.

اما چه زمانی این موضوع مشکل ساز می شود؟

جاوا اسکریپت پس از  HTML و CSS سومین بخش مهم “برنامه نویسی وب” و سایت های اینترنتی است. البته جاوا اسکریپت یک زبان کامل نیست و همانطورکه از نامش هم پیداست یک زبان اسکریپت نویسی است.

در سال های اخیر زمانی که صحبت از سایت های اینترنتی به میان می آید، اصول سئو بسیار خودنمایی می کنند.

نحوه عملکرد service worker چگونه است؟

سرویس ورکر یک اسکریپت است که مرورگر به صورت مجزا از کد های سایت به آن می پردازد. همین امر باعث دور زدن single thread بودن جاوا اسکریپ می شود. اجرای سرویس ورکر در بک گراند انجام می شود.

سرویس ورکر در واقع یک JavaScript Worker می‌باشد که مرورگر آن‌را در یک Process مجزا از وب‌سایت اجرا می کند و به صورت مستقیم به DOM یا همون کدهای html , javascript وب سایت دسترسی ندارد و برای تعامل با وب سایت از قابلیتی به نام postMessage که توسط مرورگر ارائه می‌شود استفاده می‌کند.

جاوااسکریپ زبانی است که فقط در یک Thread اجرا می‌شود ، به زبان ساده یعنی اینکه کل اسکریپت‌هایی که در یک وب سایت اجرا می شوند به صورت پشت سرهم می باشند و باید یه خط کد یا یک تابع تمام شود تا خط بعدی و تابع بعدی اجرا شود ، به همین دلیل وقتی یک دیالوگ alert باز می شود تا زمانی که آن‌را نبندیم امکان انجام هیچ کار دیگری نمی باشد.
پس استفاده از JavaScript Worker که در واقع اسکریپتی است که در Thread ی دیگر و مجزا از اسکریپت وب‌سایت اجرا می شود و قابلیتی است که توسط مرورگر ها ارائه می شود به ما امکان انجام کارهایی نظیر اسکریپت‌های طولانی و انجام کارهایی که زمان بیشتری طول می کشد را می دهد.

این سرویس قابلیت های متعددی ارائه می دهد که برخی از آن ها عبارتند از:

  • برای نمایش اعلان های وب (push notifications)
  • کش کردن برخی از بخشهای سایت مانند استایل ها ، اسکریپتها و ریکوئست های وب سایت
  • پیاده سازی کردن تجربه کاربری آفلاین
  • انجام عملیات های سنگین و زمان بر و نمایش نتیجه آن در وب سایت
  • دانلود کردن فایل هایی که توسط کلاینت ساخته شده
  • استفاده از سرویس ورکر در PWA ها

با قرار دادن یک سرویس ورکر در کد های جاوا اسکریپت، ابتدا مرورگر آن را نصب می کند. بعد از نصب، سرویس ورکر شروع به کش کردن اطلاعات ایستای سایت می کند.

چرخه کارکرد سرویس ورکر (Service worker life cycle)

 

Service worker life cycle

سرویس ورکر را ابتدا باید در کد اصلی پیاده سازی کرد. با اینکه اکثر مرورگر ها از سرویس ورکر پشتیبانی می کنند، اما بهتر است که در ابتدا از این مسئله اطمینان حاصل کنیم. (تاییدیه گرفتن از مرورگر در ابتدای کد نویسی سرویس ورکر)

زمانی که مرورگر با کد های سرویس ورکری مواجه می شود، ابتدا شروع به نصب آن در پس زمینه می کند. اگر نصب موفقیت آمیز باشد، سرویس ورکر شروع به کش کردن بخش های تعیین شده از سایت می کند.

در حالت نصب موفق، سرویس ورکر دو حالت دارد:

  • حالت بیکار یا  idle
  • حالت عمل یا fetch/message

در این حالت سرویس ورکر دو وضعیت دارد یا به حالت ساکن (idle) در می ‌آید تا رم و منابع سیستم را الکی استفاده نکند و یا در وضعیت عمل کردن (fetch/message) به وظیفه ای که برای آن فعال شده است می پردازد. پس از آن سرویس ورکر به حالت idle می‌رود و در صورتی که درخواستی با message و یا fetch نداشته باشد برای کاهش مصرف رم (RAM) متوقف می‌شود و تمامی متغیرهای محلی آن از حافظه‌ی رم پاک می‌شوند. به همین علت لازم است در صورتی که می‌خواهید دیتایی (Data) رو در بین ری‌استارت‌های مختلف نگهداری کنید لازم است که آن ها را در IndexedDB ذخیره کنید و سپس در استارت بعدی مقادیر مورد نیاز را از آن بخوانید.

دو نکته مهمی که در مورد service worker باید بدانیم!

  • یکی از قابلیت های خوبی که سرویس ورکر ها بوجود می آوردند، این است که کاربر در حالت آفلاین هم می تواند سایت را بازدید کند (سایتی که از قبل لود شده باشد).
service worker offline
  • به خاطر اجرا شدن سرویس ورکر ها در بک گراند و عدم تداخل با کد های جاوا اسکریپت، سرعت لود صفحه بالا می رود.

مواردی که قبل از استفاده از سرویس ورکر باید بدانیم :

برای استفاده از سرویس ورکر ابتدا باید مرورگر از آن پشتیبانی کند که در این زمان بیشتر ورژن های گوگل کروم ، فایرفاکس ، اپرا و برخی مرورگرهای دیگر از آن پشتیبانی می کنند.

نکته ی دیگر در استفاده از سرویس ورکر این است که سرویس ورکر فقط در وب سایت‌هایی که از https استفاده می کنند کار می کند و به این خاطر می باشد که چون سرویس ورکر می تواند تمامی ریکوئست ها و پاسخ های یک وب سایت را کاملا به عنوان یک واسط کنترل و حتی تغییر دهد ، پس برای اطمینان از امنیت وب سایت ، محیط سرویس ورکر باید https باشد.

البته قابل ذکر است که برای توسعه و تست در محیط لوکال (localhost) نیازی به https نمی باشد و سرویس ورکر در این محیط کار می کند.

فایل سرویس ورکر را باید در فولدر اصلی (روت) وب سایت قرار دهید تا بتواند تمامی آدرس های وب سایت را تحت کنترل قرار دهد ، البته این کار اجباری نمی باشد و مثلا می توانید سرویس ورکر را در آدرس /blog قرار دهید و در این صورت سرویس ورکر فقط آدرس هایی که با /blog شروع می شوند را کنترل می کند.

نحوه ایجاد سرویس ورکر

برای ساخت یک ورکر جدید به شکل زیر عمل می‌کنیم : (ورکرها را می‌توان در رشته اصلی و یا ورکرهای دیگر ساخت.)

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

همانطور که می‌بینید برای ساخت یک ورکر کافی است سازنده (constructor) آن را با آدرس یک فایل اسکریپت (script) اجرا کنیم تا ورکر شروع به دانلود و اجرای آن اسکریپت کند.

برای ارتباط میان رشته اصلی (main) و ورکر به این شکل عمل می‌شود که برای ارسال پیام از تابع postMessage استفاده می‌شود و برای دریافت پیام نیز بر روی رخداد message گوش خواهیم داد.

// main script
var myWorker = new Worker('worker.js');
myWorker.postMessage([first.value, second.value]);
myWorker. = function(e) {
  result.textContent = e.data;
  console.log('Message received from worker');
}
// worker.js
self. = function(e) {
  console.log('Message received from main script');
  var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
  console.log('Posting message back to main script');
  self.postMessage(workerResult);
}

همانطور که در بالا قابل مشاهده است در اسکریپت اصلی با استفاده از ابجکت myWorker پیام‌ها ارسال و دریافت می‌شد در حالی که در اسکریپت ورکر self برای اشاره به ورکر به کار می‌رود.

پس از آنکه کارتان با ورکر موردنظر تمام شد نیاز است تا به کار آن خاتمه دهید که با دستور زیر قابل انجام است.

 myWorker.terminate()

ورکرها انواع مختلفی همچون DedicatedWorker ، SharedWorker و ServiceWorker دارند، در SharedWorker ها ورکر ساخته‌شده می‌تواند در بین چند worker/window/iframe به طور اشتراکی استفاده شود در حالی که DedicatedWorker فقط در جایی که ساخته شده است قابل استفاده است. در بالا ما از DedicatedWorker استفاده کردیم ولی قواعد کلی برای SharedWorker ها نیز برقرار است.

در ادامه نگاهی دقیق‌تر به سرویس ورکر (Service Worker) خواهیم داشت.

سرویس ورکر نوع خاصی از ورکر است که می‌تواند رابط بین سایت ما و مرورگر باشد. این ورکر می‌تواند وظایفی را که نیاز به رابط کاربری user-interface ندارد به‌صورت پس‌زمینه (background) انجام دهد. همچنین با توجه به آنکه اجرای آن نیازمند یک پنجره‌ی فعال از سایت شما نیست، مرورگر می‌تواند حتی در صورت بسته بودن تمام پنجره‌ها نیز در صورت نیاز با این ورکر صحبت کند و درخواست‌هایی را برای ما انجام دهد.

برای مثال قابلیت هایی که با استفاده از سرویس ورکر می‌توانیم به آن‌ها دست یابیم شامل:
- offline-experiences : باز شدن و استفاده از نرم‌افزار تحت وب بدون داشتن اینترنت
- background-syncs :‌ انجام برخی عملیات‌های همگام‌سازی در پس‌زمینه
- push notifications : دریافت و نمایش اعلان از سرور بدون نیاز به باز بودن سایت

به‌صورت کلی بیشتر رفتارهای این ورکر همانند ورکرهای عادی با استفاده از , postMessage است ولی این ورکر می‌تواند به عنوان network proxy نیز عمل کند و با استفاده از رخداد onfetch به درخواست‌های صادر شده از سایت جواب دهد. همچنین می‌تواند عملیات‌هایی همچون caching نیز انجام دهد.

نحوه رجیستر کردن سرویس ورکر

برای نصب سرویس ورکر باید آنرا درون کد وب سایت تان رجیستر کنید. کد زیر به مرورگر می گوید که در صورتی که از سرویس ورکر پشتیبانی میکند بعد از لود شدن کامل صفحه سرویس ورکر با فایل sw.js که در فولدر روت قرار گرفته است را رجیستر کند.

if ('serviceWorker' in navigator){
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js')
            .then(() => console.log("ServiceWorker registerd successfully"))
            .catch((e) => console.log("ServiceWorker failed to register", e));
    })
}

در صورتی که کد بالا را در وب‌سایت تان قرار دهید هر بار که صفحه ریلود می شود کد بالا مجدد اجرا می شود و در صورتی که از قبل سرویس ورکر فعال باشد ، کد بالا باعث رجیستر شدن سرویس ورکر جدید نمی شود.

در مرورگر کروم می توانید تمامی سرویس ورکرها و وضعیت آن ها را با باز کردن صفحه inspect مرورگر توسط کلید های Ctrl+Shift+I و رفتن به تب Application و سپس انتخاب منو Service Workers مشاهده کنید. برای مشاهده‌ی لیست سرویس ورکر‌های نصب‌شده در مرورگرتان می‌توانید به آدرس chrome://inspect/#service-workers مراجعه کنید.

در کد سرویس ورکر می‌توانید با دریافت رخداد install مراحل نصبی که مورد نظرتان است شامل cache کردن فایل های استاتیک و یا کارهای دیگر را انجام دهید.

self.addEventListener('install', function(event) {
  const promise = doInstallSteps();
  event.waitUntil(promise);
});

در قطعه‌کد بالا از تابع waitUntil استفاده شده است. وظیفه‌ی این تابع دریافت کردن یک promise می‌باشد تا متوقف شدن سرویس ورکر را تا زمان به نتیجه رسیدن پرامیس موردنظر به تاخیر بیاندازد.

برای مدیریت راحت‌تر cache و offline-experience می‌توانید از لایبرری workbox استفاده نمایید.

از رخدادهای مهم دیگر موجود در سرویس ورکر می‌توان به push و notificationclick برای دریافت اطلاعات از سرور به‌صورت push و نمایش اعلان و مدیریت دکمه‌های قابل مشاهده در اعلان و sync برای ارسال اطلاعات به سرور حتی پس از بسته شدن پنجره‌ی سایت اشاره کرد.

تابع self.skipWaiting()

تابع SkipWaiting یک نجات دهنده زندگی است. این تابع تضمین می کند که نسخه جدید یک سرویس دهنده، صفحه را در اختیار گرفته و بلافاصله فعال شود.

برای درک اهمیت و کاربرد این تابع، ما نیاز داریم تا چرخه حیات سرویس ورکر را که در بالا به آن اشاره شد را مرور کنیم. یک سرویس ورکر در طول چرخه حیات خود می تواند در شش وضعیت زیر باشد:

Parsed

Installing

Installed (Waiting)

Activing

Activated

Redundant

وقتی ما با تابع navigator.serviceWorker.register() یک سرویس ورکر را رجیستر می کنیم، آن فایل parse می شود و وضعیت سرویس ورکر به Parsed تغییر می کند. با فرض اینکه خطایی رخ ندهد، سرویس ورکر Installed می شود. برای صفحه ای که قبلا سرویس ورکری نداشته باشد، سرویس ورکر جدید بلافاصله Activated می شود.

ولی اگر صفحه در حال حاضر یک فایل سرویس ورکر فعال داشته باشد، قضیه کمی پیچیده تر می شود.

انتظار بی پایان

اگر صفحه در حال حاضر یک سرویس ورکر فعال داشته باشد و فایل جدید push شود، فایل جدید parse و سپس install می شود. فایل install شده حالا منتظر اولین فرصت است تا فعال (Active) شود.

 

https://dev.to/gelopfalcon/service-worker-and-its-self-skipwaiting-44o5