初学pwa--service worker 记录

简介

pwa的技术层面

  • 安全
  • 性能
  • 体验

pwa的特性

  • 渐进式:开发宗旨,兼容所有浏览器
  • 连接无关性:利用service worker开另一个线程进行运行复杂逻辑,可以在网络较差的地方进行
  • 安全:通过https协议进行服务或者在本地的localhost 127.0.0.1进行
  • 可索引:
  • 粘性:可以利用manifest.json进行离线存储,并且可以离线通知
  • 可安装
  • 可链接
  • 持续更新
  • 类似应用:Native app的交互和导航,有Native app的体验

离线和缓存

service worker

简介

常用优化性能手段
  • cdn
  • css sprite雪碧图
  • 文件合并压缩
  • 异步加载
  • 资源缓存
  • 减少dns请求(将图片存于同一个域名下)
  • 进行cookie隔离
  • 避免重定向
关于解放主线程

对于复杂的逻辑,可以放在另一线程,不放在主线程,这与web worker操作极其相似,但是存在一些区别

service worker web worker
必须在https环境下进行工作 不需要
一旦install就一直存在
用的时候直接唤醒 不用的时候自动睡眠
离线内容开发者可控
可编程拦截代理请求和返回,缓存的文件可以被网页进程取到,包括离线状态
不能直接操作dom不能用alert这些全局函数 同样
异步实现,内部大部分是通过promise实现 同样

如何使用service worker

依赖
  • 必须是https或者是本地localhost 127.0.0.1
  • 缓存机制是Cache API
  • 请求是fetch API
  • 基于promise
注册
if ('serviceWorker' in navigator) {
    window.addEventListener('load', function () {
        navigator.serviceWorker.register('/server.js', {scope: '/'}) // 定义相关文件的位置,scope为子目录文件夹名称
            .then(function (registration) {

                // 注册成功
            })
            .catch(function (err) {

                // 注册失败:
            });
    });
}

chrome://inspect/#service-workers 进行查看是否已经注册

安装

一般是用来填充浏览器的离线缓存能力,可以存储网络发来的资源,并且根据请求来生成key,

// 监听 service worker 的 install 事件
this.addEventListener('install', function (event) {
    // 如果监听到了 service worker 已经安装成功的话,就会调用 event.waitUntil 回调函数
    event.waitUntil(
        // 安装成功后操作 CacheStorage 缓存,使用之前需要先通过 caches.open() 打开对应缓存空间。
        caches.open('my-test-cache-v1').then(function (cache) {
            // 通过 cache 缓存对象的 addAll 方法添加 precache 缓存
            return cache.addAll([
                '/',
                '/index.html',
                '/main.css',
                '/main.js',
                '/image.jpg'
            ]);
        })
    );
});

由于localstorage是同步的做法,所以不允许在service worker上使用

请求响应

每次service worker控制的资源被请求到时,就会触发fetch事件,这些包括scopr指定的所有html文档,和这个HTML引用的所有任何资源。

this.addEventListener('fetch', function (event) {
    event.respondWith(
    // 劫持HTTP响应
        caches.match(event.request).then(function (response) {
            

            // 如果 Service Worker 有自己的返回,就直接返回,减少一次 http 请求
            if (response) {
                return response;
            }

            // 如果 service worker 没有返回,那就得直接请求真实远程服务
            var request = event.request.clone(); // 把原始请求拷过来
            return fetch(request).then(function (httpRes) {

                // http请求的返回已被抓到,可以处置了。

                // 请求失败了,直接返回失败的结果就好了。。
                if (!httpRes || httpRes.status !== 200) {
                    return httpRes;
                }

                // 请求成功的话,将请求缓存起来。
                var responseClone = httpRes.clone();
                caches.open('my-test-cache-v1').then(function (cache) {
                    cache.put(event.request, responseClone);
                });

                return httpRes;
            });
        })
    );
});
  • install 的优点是第二次访问即可离线,缺点是需要将需要缓存的 URL 在编译时插入到脚本中,增加代码量和降低可维护性
  • fetch 的优点是无需更改编译过程,也不会产生额外的流量,缺点是需要多一次访问才能离线可用。
缓存需要更新
  • 在install中执行self.skipWaiting(),然后进入activate阶段,执行self.client.claim(),更新客户端所有的service worker
// 安装阶段跳过等待,直接进入 active
self.addEventListener('install', function (event) {
    event.waitUntil(self.skipWaiting());
});

self.addEventListener('activate', function (event) {
    event.waitUntil(
        Promise.all([

            // 更新客户端
            self.clients.claim(),

            // 清理旧版本
            caches.keys().then(function (cacheList) {
                return Promise.all(
                    cacheList.map(function (cacheName) {
                        if (cacheName !== 'my-test-cache-v1') {
                            return caches.delete(cacheName);
                        }
                    })
                );
            })
        ])
    );
});

如果删除了cache上的键,但是浏览器却缓存了,那么就对这些文件设置更短的缓存期或者过滤规则

手动更新sw

使用Registration.update()更新这个页面

var version = '1.0.1';

navigator.serviceWorker.register('/sw.js').then(function (reg) {
    if (localStorage.getItem('sw_version') !== version) {
        reg.update().then(function () {
            localStorage.setItem('sw_version', version)
        });
    }
});

如果该文件已 24 小时没有更新,当 Update 触发时会强制更新。这意味着最坏情况下 Service Worker 会每天更新一次

生命周期

  • 安装
    • 此时可以对静态资源进行缓存
    • 回调方法
      • event.waitUntil() 传入一个Promise为参数,等到promise为resolve为止
      • self.skipWaiting() 强制waiting进入activate状态
  • 安装后 等待其他的service worker线程被关闭
  • 激活
    • 已经清除了其他worker或者关联缓存的旧缓存资源
    • 回调函数
      • event.waitUntil()
      • self.clients.claim()取得页面控制权。每次打开这个页面都会去使用,旧版本不能控制
  • 激活后 会对activate事件进行回调,可以更新缓存,可以处理fetch,sync(后台同步),push(推送)的事件
  • 废弃

这里我有一个问题:service worker里针对不同注册安装的文件有不同的worker,这个worker是为所有注册这个的页面服务的,那一个页面进行注册安装之后,其他的页面在注册过后,还需要安装吗,

调试sw

  1. 首先在开发环境需要跳过Install的等待状态,利用self.skipWaiting()
  2. CHROME浏览器的application有service worker的选项
  3. 也可以查看cache storage的缓存内容
  4. fetch 请求都会记录在network之上的

你可能感兴趣的:(前端学习,前端开发学习流程)