PWA之 Service worker

  渐进式 Web 应用(Progressive Web Apps,也被称为 PWAs)是 Web 技术方面一项令人兴奋的创新。PWA 混合了多项技术,能够让 Web 应用的功能类似于原生移动应用。它为开发人员和用户带来的收益能够突破纯 Web 解决方案和纯原生解决方案的限制:  

  1. 你只需要一个按照开放、标准 W3C Web 技术开发的应用,不需要开发单独的原生代码库;
  2. 用户在安装之前就能发现并尝试你的应用;
  3. 没有必要使用 AppStore,无需遵循复杂的规则或支付费用。应用程序会自动更新,无需用户交互;
  4. 用户会被提示“安装”,这样会添加一个图标到主屏幕上;
  5. 当启动的时候,PWA 会展现一个有吸引力的启动画面;
  6. 如果需要的话,浏览器的 chrome 选项可以进行修改,以便于提供全屏的体验;
  7. 基本文件会在本地缓存,所以 PWA 要比标准 Web 应用反应更快(它们甚至能够比原生应用更快);
  8. 安装是轻量级的,可能只需几 KB 的缓存数据;
  9. 所有的数据交换必须要通过安全的 HTTPS 连接来执行;
  10. PWA 支持离线功能,当网络恢复后,数据会进行同步。

  service worker 本意为渐进式网络应用(progressive web app, PWA)提供离线支持,使得网络应用可以离线运行。一旦启用 service worker ,则它可以根据开发者的缓存配置为用户缓存网站静态与动态资源,并截获用户的所有网络请求,并根据缓存配置来决定是从缓存还是网络获取相应资源,从而可以提高网页的加载速度。测试结果表明,一般能实现 4-5 倍的加速,最好的时候能够实现 10 倍的加速。使用 service worker 实现网站加速的优势有:

  • 可以很轻易地实现静态与动态资源缓存,决定缓存空间的大小与缓存时间期限,可定制性高;
  • 不需要服务端支持,只需要在本地生成 service worker 文件并上传就可以使用,特别适用于没有服务端的静态博客或网站;
  • 配合 sw-precache ,只需要做好缓存配置, sw-precache 可以自动生成 service woker 文件,不需要自己实现缓存逻辑;
  • 可以灵活为动态与静态资源,以及不同网址提供不同的缓存机制,并实现资源的动态更新,同样不需要自己编写代码

  Service workers 作为一个独立的线程,运行环境和普通环境不同,本质上充当Web应用程序与浏览器之间的代理服务器。service worker可以:

  • 后台消息传递
  • 网络代理,转发请求,伪造响应
  • 离线缓存
  • 消息推送
  • … …

  在目前阶段,ServiceWorker的主要能力集中在网络代理和离线缓存上。具体的实现上,可以理解为ServiceWorker是一个能在网页关闭时仍然运行的WebWorker。

ServiceWorker的生命周期

  一个ServiceWorker会经历:安装、激活、等待、销毁的阶段。

这张图把ServiceWorker的声明周期分为了两部分,主线程中的状态和ServiceWorker子线程中的状态。子线程中的代码处在一个单独的模块中,当我们需要使用ServiceWorker时,按照如下的方式来加载:

 Install 

  这个时候ServiceWorker处于Parsed解析阶段,ServiceWorker处于Installing安装阶段,主线程的registration的installing属性代表正在安装的ServiceWorker实例。如果之前没有serviceWorker实例,或者之前有serviceWorker实例但serviceWorker文件有更新,这时子线程中才会触发install事件,可以在install事件中指定缓存资源。

这里使用了Cache API来将资源缓存起来,同时使用e.waitUntil接手一个Promise来等待资源缓存成功,等到这个Promise状态成功后,ServiceWorker进入installed状态,意味着安装完毕。


const self = this;const HOST_NAME = location.host;const VERSION_NAME = ‘CACHE-v5‘;const CACHE_NAME = HOST_NAME + ‘-‘ + VERSION_NAME;const CACHE_HOST = [HOST_NAME, ‘0.plus‘, ‘icms.biyong.io‘];
var cacheList = [
    "./css/common.css",
    "./css/discover.css",
    "discover.html",
]

const onInstall = function (event) {
    console.log(‘触发install事件--------‘);
    // 打开一个缓存空间,将相关需要缓存的资源添加到缓存里面
    event.waitUntil(
        caches
            .open(CACHE_NAME)
            .then(function (cache) {
                self.skipWaiting();
                console.log(‘Install success---------------‘);
                return cache.addAll(cacheList)
            })
    );
};

// 当浏览器解析完sw文件时,serviceworker内部触发install事件
self.addEventListener(‘install‘, onInstall);

然而这个时候并不意味着这个ServiceWorker会立马进入Activate阶段,除非之前没有新的ServiceWorker实例,如果之前已有ServiceWorker,新的ServiceWorker安装完成后会延时激活并进入了waiting状态,浏览器仍在运行之前的ServiceWorker,那么需要满足如下任意一个条件,新的ServiceWorker才会进入Activate阶段:

  • 在新的ServiceWorker线程代码里,使用了self.skipWaiting()
  • 或者当用户导航到别的网页,因此释放了旧的ServiceWorker时候
  • 或者指定的时间过去后,释放了之前的ServiceWorker

 Activate 

这个时候ServiceWorker的生命周期进入Activating阶段,ServiceWorker子线程接收到activate事件,这个时候通常做一些缓存清理工作,当e.waitUntil接收的Promise进入成功状态后,ServiceWorker的生命周期则进入activated状态。这个时候主线程中的registration的active属性代表进入activated状态的ServiceWorker实例。

const onActive = function (event) {
    event.waitUntil(
        caches
            .keys()
            .then(function (cacheNames) {
                return Promise.all(
                    cacheNames.map(function (cacheName) {
                        // active事件中通常做一些过期资源释放的工作
                        if (CACHE_NAME.indexOf(cacheName) === -1) {
                            return caches.delete(cacheName);
                        }
                    })
                );
            })
            .then(function () {
                console.log(‘active claim success 2-------------‘);
                self.clients.claim();
            })
    );
};

// 如果当前浏览器没有激活的service worker或者已经激活的worker被解雇,
// 新的service worker进入active事件
self.addEventListener(‘activate‘, onActive);

  到此一个ServiceWorker正式进入激活状态,可以拦截网络请求了。如果主线程有fetch方式请求资源,那么就可以在ServiceWorker代码中触发fetch事件。

const onFetch = function (event) {
    event.respondWith(handleFetchRequest(event.request));
};

const handleFetchRequest = function (req) {
    const request = req;
    if (isCORSRequest(req.url, HOST_NAME)) {
        const request = new Request(req.url, {mode: ‘no-cors‘});
    }
    return caches.match(request)
        .then(function (response) {
            if (response) {
                return response;
            } else {
                console.log(‘缓存没找到‘ + request.url);
            }
        })

    const request = req;
    if (isCORSRequest(req.url, HOST_NAME)) {
        const request = new Request(req.url, {mode: ‘no-cors‘});
    }
    return fetch(request)
        .then(function (response) {
            console.log(request.url + ‘请求回来了‘);
            // online: Return the response if need
            if (isNeedCache(req) && isValidResponse(response)) {
                const clonedResponse = response.clone();
                caches
                    .open(CACHE_NAME)
                    .then(function (cache) {
                        cache.put(request, clonedResponse);
                        console.log(‘添加缓存: ‘ + request.url);
                    })
            }
            return response;
        })
        .catch(error => {
            // offline: Return the caches
            console.log(‘fetch ‘ + request.url + ‘ fail: ‘ + error.message);
            return caches.match(request)
                .then(function (response) {
                    if (response) {
                        return response;
                    } else {
                        console.log(‘缓存没找到‘ + request.url);
                    }
                })
        })

};

self.addEventListener(‘fetch‘, onFetch);

 Asw-precache模块 

文档:https://www.npmjs.com/package/sw-precache

  sw-precache也是NODE中的一个模块,可以通过npm install sw-precache来进行安装。sw-precache可以配合多个工具使用,这里我主要介绍一下如何配合gulp来使用。

我们通过利用sw-precache来生成service-worker.js文件。主要的方式是检测你在staticFileGlobs里面的文件有没有发生变化,如果发生变化就会重新生成hash码,自动更新service-worker.js文件。从而能够使得APP在代码更新之后,浏览器通过字节逐一解析到服务器的service-worker.js不一样了,缓存Cache中的数据才会重新向远程请求新的代码。

缓存资源更新

(缓存问题)如果当前已有serviceWorker实例, 并将某些数据缓存在了cache中 当服务器上这些缓存的数据更新时,浏览器请求到的数据始终是serviceWorker的缓存cache中的旧内容。 只有服务器更新了service-worker.js文件,浏览器通过字节逐一解析到新的service-worker.js不一样了,缓存Cache中的数据才会重新更新。

 

原文地址:https://www.cnblogs.com/Tangttt/p/9568563.html

时间: 2024-08-02 07:10:42

PWA之 Service worker的相关文章

[PWA] 2. Service worker life cycle

Once serive worker is registered, the first time we go to the app, we cannot see the logs from servcie works. Any only refersh it second time, then we able to see the logs. Once we change service worker, it doesn't seem that we have change it. The No

[PWA] 1. Intro to Service worker

Service worker stays between our browser and noetwork requests. It can help to fetch data from cache and cache the data from Internet. To get our service worker, we need to : Register the service worker. Service worker in our code is just a javascirp

借助Service Worker和cacheStorage缓存及离线开发 (转载)

一.缓存和离线开发 说得HTML5离线开发,我们通常第一反应是使用html5 manifest缓存技术,此技术已经出现很多年了,我以前多次了解过,也见过一些实践案例,但是却从未在博客中介绍过,因为并不看好. 为什么不看好呢?用一句话解释就是“投入产出比有些低”. 对于web应用,掉线不能使用是理所当然的,绝不会有哪个开发人员会因为网页在没网的时候打不开被测试MM提bug,或者被用户投诉,所以,我们的web页面不支持离线完全不会有什么影响.但如果我们希望支持离线,会发现,我投入的精力和成本啊还真不

Service Worker和HTTP缓存

很多人,包括我自己,初看Service Worker多一个Cache Storage的时候,就感觉跟HTTP长缓存没什么区别. 例如大家讲的最多的Service Worker能让网页离线使用,但熟悉HTTP缓存的朋友,会发现,把整站所有资源设置为长缓存(不带校验),也可以实现离线使用. 那么,Service Worker在缓存方面和HTTP缓存比较,有什么好处呢? 带着这个疑问,我翻阅了一些大神博客 JakeArchibald的<Caching best practices & max-ag

PWA之Service work

原文 简书原文:https://www.jianshu.com/p/84a4553d81a8 大纲 1.Service Workers: PWA 的关键 2.理解 Service Workers 3.Service Worker 生命周期 4.Service Worker 基础示例 1.Service Workers: PWA 的关键 正如我之前所提到的,释放 PWA 力量的关键在于 Service Workers .就其核心来说,Service Workers 只是后台运行的 worker 脚

认识 service worker

离线缓存可以提升用户体验,可以节省网络资源,但是,浏览器对资源缓存和自定义网络请求的控制一直不够完善,service worker 的出现就是为了解决这些问题 它可以解决目前离线应用的问题,同时也可以做更多的事. Service Worker 可以使应用先访问本地缓存资源,所以在离线状态时,在没有通过网络接收到更多的数据前,仍可以提供基本的功能(Offline First).这是原生APP 本来就支持的功能,这也是相比于 web app,原生 app 更受青睐的主要原因. 开始使用 有些浏览器版

service worker 消息推送

https://developers.google.com/web/fundamentals/codelabs/push-notifications/?hl=en 首先下载源码: git clone https://github.com/GoogleChrome/push-notifications.git 设置如下选项方便开发: 开始 注册之后记录sw实例: navigator.serviceWorker.register('sw.js') .then(function(swReg) { co

Service Worker基础知识整理

Service Worker是什么 service worker 是独立于当前页面的一段运行在浏览器后台进程里的脚本.它的特性将包括推送消息,背景后台同步, geofencing(地理围栏定位),拦截和处理网络请求. 这个 API 会让人兴奋的原因是,它可以使你的应用先访问本地缓存资源,所以在离线状态时,在没有通过网络接收到更多的数据前,仍可以提供基本的功能(一般称之为 Offline First). 在 service worker 之前,另一个叫做 APP Cache 的 api 也可以提供

service worker

这是配置的sw.js 已测试,是OK的. 'use strict'; const version = 'v2'; const __DEVELOPMENT__ = false; const __DEBUG__ = true; const offlineResources = [ './tt.html', './images/1.png', // '/imgerror.jpg', // '/favicon.ico' ]; const ignoreCache = [ /https?:\/\/hm.ba