آشنایی با Worker ها (۳)

تا اینجا با وب ورکر ها آشنا شدیم اگر باهاشون آشنایی ندارین میتونین این ۲ پست رو بخونین:

https://virgool.io/@arainjast/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-worker-%D9%87%D8%A7-%DB%B1-y5ahwihwowgr
https://virgool.io/@arainjast/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-worker-%D9%87%D8%A7-%DB%B2-rswz61tyxuxj

نوع دیگری از ورکر ها Service Worker ها هستن که در ادامه باهاشون بیشتر آشنا میشیم.

آشنایی با Service Worker ها

سرویس ورکر ها میتونن کارهایی رو در پشت صحنه انجام بدن. چرا میگم پشت صحنه چون سرویس ورکر ها در Thread دیگه ای غیر از Thread اصلی که که فایل های Html و JS هستن اجرا میشن یعنی بر خلاف فایل های JS ئی که جداگانه برای هر page لود میشوند و Attach میشن به فایل HTML و همگی در یک Thread اجرا میشوند سرویس ورکرها فایل های جاوا اسکریپتین که به صورت جدا گانه جدا از HTML و در Thread ئی دیگر فعال هستند. و تمام پیج ها وصفحات در یک دامنه رو مدیریت میکنن. و حتی هنگامی که پیج بسته میشود هم فعال هستند و در تمام مدت به Event (رویداد) های خاصی Listen (گوش) میکنند.

چه رویداد های خاصی؟

سرویس ورکر ها فقط به یک سری رویدادهای خاص گوش میکنند که این موارد هستند:

۱- رویداد Fetch

هنگامی که Browser یا شما (در فایل جاوااسکریپت در یک پیج) یک HTTP Request ارسال میکنید Browser ابتدا چک میکنه که سرویس ورکری register شده یا نه اگر نشده باشه که درخواست رو به network میفرسته ولی اگر رجیستر شده باشه رویداد Fetch رو به سرویس ورکر میفرسته و سرویس ورکر تصمیم میگیره با این رویداد چیکار کنه. یه نکته ای که هست اینه که اگر شما درخواستتون رو از طریق خود Fetch بفرستین این درخواست به سرویس ورکر میره ولی اگر شما درخواستتون رو از طریق XMLHttpRequest یا (XHR) بفرستین رویداد Fetch به سرویس ورکر ارسال نمیشه. اگر با Fetch آشنایی ندارین هم میتونین این پست رو ببینین.

https://virgool.io/@arainjast/%DB%8C%D8%A7%D8%AF%DA%AF%DB%8C%D8%B1%DB%8C-fetch-api-%D8%A8%D8%A7-%D8%B3%D8%A7%D8%AE%D8%AA-%DB%8C%D9%87-%DA%A9%D8%AA%D8%A7%D8%A8%D8%AE%D9%88%D9%86%D9%87-%D8%B3%D8%A7%D8%AF%D9%87-http-wv8hmp6rnx2a

۲- رویداد Push Notification

جدیدا سایت ها هنگام ورودتون ازتون میخوان که اجازه بدین Notification براتون بفرستن و شما اگر اجازشو داده باشین میبینین که حتی هنگامی که پیجشون باز نیست Notification اش براتون میاد این کار سرویس ورکره چون همونطور که فهمیدیم حتی زمانی که پیجشون بسته شده باز هم به رویداد هایی گوش میکنن که یکیشون رویداد Push Notification هست. روند کار اینطور هست که هر مرورگری که Push Notification رو ساپورت میکنه یک سرور پوش هم Vendor اش داره‌ (برای مثال گوگل برای کروم و موزیلا برای فایرفاکس) و شما از طریق سرورتون به سرور پوششون یک Push Notification ارسال کنین تا انها این Notification رو براتون به مرورگر ارسال کنند.

۳- رویداد Notification Interaction

رویدادی که کاربر پس از نمایش Notification و تعامل (Interact) با آن انجام میدهد برای سرویس ورکر ارسال میشود.

۴- رویداد Background Sync

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

۵- رویداد های Service Worker Lifecycle

وقتی سرویس ورکر از حالتی به حالت دیگر میرود رویدادهایی داریم که میتوان به انها در سرویس ورکر گوش داد.

چرخه حیات Service Worker ها

سرویس ورکر حالات مختلفی داره برای این که بتونیم به درستی با اونها کار کنیم باید این حالات رو بدونیم. در قدم اول سرویس ورکر نیاز داره که register بشه . برای register شدن پس از باز کردن یک صفحه و load شدن فایلهای js در انها سرویس ورکر register میشه و پس از register شدن به گام اول چرخه حیاتش یعنی install میره و رویداد install رو داریم یکی از مواردی که میشه توی این رویداد انجام داد کش کردن asset ها مثل html,css,js هست. پس از install شدن سرویس ورکر میخواد به حالت activate بره ولی این حالت الزاما پس از اتمام نصب سرویس ورکر نیست بلکه بستگی داره که سرویس ورکری که register شده نسخه قبلی ئی داشته که ما نسخه جدید رو رجیستر کردیم یا یک سرویس ورکر جدید ئه. سرویس ورکر وقتی فعال میشه که نسخه قبلی در حال اجرا نباشه. برای این منظور اگر سرویس ورکر قبلی در حال اجرا باشه و متوقف کردنش باید تبش بسته بشه و دوباره صفحه لود بشه تا نسخه جدید جایگزین نسخه قبلی شده و سرویس ورکر به حالت activate بره پس از رفتن به حالت activate رویدادش اجرا میشه و پس از ان سرویس ورکر کنترل پیج های در scope خودش رو در اختیار میگیره. دقت داشته باشیم که برای install شدن و active شدن یک سرویس ورکر نیاز هست که یا یک سرویس ورکر جدید رجیستر بشه یا سرویس ورکر قبلی تغییر کنه در اینصورت این ۲ رویداد رخ میده در غیر این صورت در صورتی که فایل سرویس ورکر تغییری نداشته باشه پس از رفرش مرورگر سرویس ورکری register نمیشه.

چون سرویس ورکر در پشت صحنه حضور داره پس از این که رویداد جدیدی براش ارسال نشه به حالت idle میره و پس از مدت زمانی نیز terminate میشه که این بدین معنی نیست که سرویس ورکر حذف میشه بلکه با رسیدن رویداد جدید دوباره فعال میشه.

ساپورت مرورگر ها

ساپورت مرورگر ها برای سرویس ورکر مناسبه و برای جزئیات بیشتر میتونین اینجا ببینین.

ثبت یک سرویس ورکر با یک مثال

حال وقتش شده که که با یک مثال یاد بگیریم چجوری میشه یک سرویس ورکر رو ثبت کرد و ازش استفاده کرد. ما در این مثال میخوایم صفحه index.htm خودمون رو با asset هاش کش کنیم تا کاربر پس از قطع ارتباط با اینترنت در حالت افلاین بتونه صفحه اصلی سایتمون رو ببینه.

ثبت سرویس ورکر بدین شکله :

//app.js
  if('serviceWorker' in navigator){
  navigator.serviceWorker
    .register('/sw.js')
    .then(()=>{
        console.log('Service Worker is registered.');
    })
  }
  

تو خط اول چک میکنیم که مرورگرمون سرویس ورکر رو ساپورت میکنه یا نه

بعد توی خط ۴ فایل sw.js که سرویس ورکرمون هست رو ثبت میکنیم که نتیجش یه promise هست که میتونیم چک کنیم که register شد سرویس ورکرمون یا نه.

* رجیستر یک پارامتر دوم اختیاری داره که میتونین scope سرویس ورکرتون رو مشخص کنین به طور مثال سرویس ورکر زیر فقط مختص scope با اون آدرس هست :

  navigator.serviceWorker
  .register('/sw-info.js', {scope:'/info'} ) 

حال نوبته سرویس ورکرمونه :

self.addEventListener('install',(event)=>{
  console.log('[service worker] installed ',event)
 })
  self.addEventListener('activate',(event)=>{
     self.clients().claim()   
     console.log('[service worker] activated ',event)
  })
   self.addEventListener('fetch',(event)=>{
      console.log('[service worker] fetch event: ',event) 
      event.respondWith(fetch(event.request)) 
   })

خب ۳ تا addEventListener برای رویداد های install,activate,fetch نوشتیم که فقط وقتی event رو لاگ میکنن.
رویداد fetch انتظار داره که پاسخی بهش بدیم بنابر این با کمک متد respondWith و رکوئستی که از طریق event داریم پاسخ رو بدون هیچ دستکاری میدهیم .
* در حالت عادی سرویس ورکر پس از اکتیو شدن کنترل صفحات را از پس از رفرش صفحه در اختیار میگیرد ولی با خط ۵ ام ما بهش میگیم که کنترل رو از همین لحظه در اختیار بگیره.

حالا وقتشه که asset هایی که میخوایم رو وارد کش کنیم و کد رویداد install رو بدین شکل بازنویسی میکنیم:

self.addEventListener('install',(event)=>{
    console.log('[service worker] installed',event)
    event.waitUntil(
        caches.open('static')
        .then(function(cache){
            cache.addAll([
                '/',
                '/index.html',
                '/src/css/style.css'
             ])
         })
      )
})

کد بالا بدین شکل کار میکنه:

خط ۳ event.waitUntil میگه که تا وقتی این دستورات تموم شده به event بعدی نرو.

خط ۴ از api ئی که Cache Storage در اختیارمون گذاشته استفاده میکنیم و با open میتونیم آبجکتی با نامی که میدهیم (در اینجا static ) در cache ایجاد کنیم. که یک promise به ما میدهد که در صورتی که موفقیت امیز باشه میتونیم از cache که به ما میده استفاده کنیم.

خط ۶ با کمک متد addAll و پاس دادن یک آرایه که آدرس فایل هایی که میخوایم کش بشن هست درخواست کششون رو میدهیم.

خب تا اینجا فایل هایی که میخواستیم کش بشن رو کش کردیم این کار بخودی خود هیچ تاثیری نمیزاره و کماکان فایل ها از نتورک درخواست میشن و آفلاین هم کاری نمیکنه بدین منظور باید با کمک رویداد fetch درخواست هارو کنترل کنیم.

self.addEventListener('fetch',(event)=>{
    event.respondWith(
        caches.match(event.request)
        .then(response=>{
            return response ? response : fetch(event.request)
            })
    )
 })

در اینجا چک میکنیم که رکوئست آیا کش شده قبلا یا خیر (خط ۳) و اگر کش شده بود رسپانس کش شده رو برمیگردونیم وگرنه رکوئست رو fetch میکنیم.

جمع بندی

در این پست با سرویس ورکرها آشنا شدیم و به صورت خیلی ابتدایی مکانیزم کش رو برای مشاهده آفلاین پیاده سازی کردیم. با کمک سرویس ورکر ها میشه وب اپلیکیشن های PWA رو پیاده سازی کرد که یکی از قدم هاش همین کش کردن و نمایش در حالت آفلاین ئه. PWA بسیار مبحث طولانی و بزرگی هست که نیاز به یک سری پست جداگانه داره که طبیعتا در این پست نمیگنجه چون هدف این پست آشنایی با سرویس ورکر ها بود. امیدوارم وقت بشه و بتونیم به صورت کامل و در یک سری پست یک PWA رو پیاده سازی کنیم.