Progressive Web App Service Worker (4)

什麽是 Service Workers

Service Workers 的角色是位於 Web App 与网路连接中间的一层 "代理网路连接",就像是秘书一样负责将资料处理後再转介给 App。

还记得第一次看到这个名词是因为看 Progressive Web App,这里比较新的观念是可以帮助 web app 在网路较慢或是没有连线时去使用快取资料。另外一个特性是 service worker 可以在页面没开启时背景执行,由於可以背景执行,所以接受推播的任务也可以在这里进行撰写,需要注意的是推播分成两部分实作,一部分是通知,一部分是接受推播,後端各家的概念上其实都是先针对 topic (可以想像成频道) 进行订阅,然後撰写接收事件,然後触发通知。

最终透过这样的技术实现,这层 "代理网路连接" 让资源能够被快取下来且能够让装置在离线时被使用,JavaScript 是单线程的语言,但是 Service Workers 会跟页面的 thread 分开运行,且不会影响到 DOM 的结构,这个概念就像是打 API 其实也是非阻塞的执行,可以在收到资料後才进行动作,同样的我们也可以把这样的任务交给 Service Worker,除了离线快取以外,也能够支援推播的处理或是让 worker 来执行一些耗能的计算。

最後要注意的是 Service Workers 在考量安全性的基础上,只能执行在 HTTPS 的环境。

Service Workers 常见用途

  1. 不同的快取策略运用
    • Network or Cache: 使用线上资源或使用快取
    • Cache only: 只使用快取
    • Cache and update: 使用快取并使用线上资源更新快取
    • Cache, update and refresh: 使用快取,但同时也用线上资源来更新快取,若有新资源就同时更新画面
  2. Web Push
    • 订阅推播
    • 推播内容样式实作

注册与使用 Service Worker

底下 Demo 了第一次先将图片 icon 快取,第二次如果发现有使用到 dog 时则用 icon 取代,可以明显看到有三个阶段,实作上就是透过这几个事件的触发行为来达到我们的目的。

  • install: 安装阶段
  • activate: 启用阶段,可以在这个阶段清除旧的快取
  • fetch: 代理网路,在这里可以决定要回覆线上的内容或是快取的内容到 Web App 中

首先第一步是去实作相关的事件内容,在 install 阶段中有个 waitUntil,白话就是必须等待安装成功後才去执行相关事件。

再来就是 cache 这个物件该怎麽去使用,初期我们就先不考虑那麽多,先照着范例进行撰写,那既然是快取,有个重点就是快取要有版本名称,程序码中我们目前就是 V1。

caches 是提供给 Service Worker 使用的特殊 CacheStorage 物件,因为 web storage 在实作上是同步机制所以无法使用,在 Service Workers 中储存都是以 Cache API 为主。

快取的 API 相关文件: https://developer.mozilla.org/en-US/docs/Web/API/Cache

self.addEventListener("install", (event) => {
  console.log("installing…");

  // cache a icon
  event.waitUntil(
    caches.open("v1").then((cache) => cache.add("images/icon.png"))
  );
});

self.addEventListener("activate", (event) => {
  console.log("ready to handle fetches!");
  // 可以在这个阶段清除旧的快取
  e.waitUntil(
    caches.keys().then((keyList) => {
      Promise.all(
        keyList.map((key) => {
          if (key === cacheName) {
            return;
          }
          caches.delete(key);
        })
      );
    })
  );
});

self.addEventListener("fetch", (event) => {
  const url = new URL(event.request.url);

  if (url.origin == location.origin && url.pathname == "/images/dog.jpg") {
    console.log(url);
    event.respondWith(caches.match("images/icon.png"));
  }
});

最後实做完成後别忘了注册,Service Worker 才会生效,这里可以透过 Chrome 的内建工具来观察:

  • chrome://inspect/#service-workers
if ("serviceWorker" in navigator) {
  navigator.serviceWorker.register("./pwa-examples/test/sw.js");
}

PWA 推播

  1. 有支援的话,就能够透过 Service Work 来使用推播功能 (swRegistration)
let swRegistration;

function initialiseUI() {
  // Set the initial subscription value
  swRegistration.pushManager.getSubscription().then(function (subscription) {
    isSubscribed = !(subscription === null);

    if (isSubscribed) {
      console.log("User IS subscribed.");
    } else {
      console.log("User is NOT subscribed.");
    }

    updateBtn();
  });
}

navigator.serviceWorker.register("sw.js").then(function (swReg) {
  console.log("Service Worker is registered", swReg);

  swRegistration = swReg;

  initialiseUI();
});

详细教学可以参考:
https://developers.google.com/web/fundamentals/codelabs/push-notifications?hl=zh-tw

Workbox

Workbox 由 google 开发维护,是一套用来强化 service worker 的工具包,方便我们更快实作出 production-ready 的 Service Worker,几种常见的快取都已经提供相关范例,其实我们只需要照抄即可。

  • Cache Google Fonts
  • Cache JavaScript and CSS
  • Cache Images
  • Precache your Files
  • Offline Google Analytics

<<:  什麽是物件导向程序设计 (Object-oriented programming)

>>:  环境配置(Day2)

[Vue] 判断图片是否存在

在开发Vue专案时,时常会使用binding的技巧,用以动态变更参数的值, 如下 <div c...

【Day 5】VSCode移动GIT里的HEAD

何谓HEAD? 说明 : 表示目前指向的档案版本指标,通常是指向最新的commit档案。 可以先透过...

[DAY-15] 认知科学中的成功之路

一半拉! 加油! YA~ 心理学的研究 其实可以协助大家思考职涯 BUT 很少人接触这方面的讯息 ...

【在 iOS 开发路上的大小事-Day06】透过 Delegate 来传值

前情提要 一般我们在做传值动作的时候,会有好几种方式可以做,像是用 Segue、Closure、De...

[13th-铁人赛]Day 9:Modern CSS 超详细新手攻略 - Specificity

今天要讲的主题是权重,权重在CSS中扮演着裁决者的角色,在被重复赋予样式时,决定最终该显示哪一个样式...