pwa--实现离线页面数据呈现

589 阅读3分钟

看掘金社区半年的时间,第一次自己动手把自己平时学习的心得发表出来,看了一些关于pwa的入门教程文章,感觉还是有点云里雾里,终于在b站上面找到了百度lavas项目分享的视频,感觉有点感觉了。

如果大家觉得我笔记比较粗糙可以去b站上自己学习(^▽^).

效果入下

1:创建sw.js文件
self.addEventListener('fetch', function(event) {
    
    console.log('request:' +event.request.url )
})
2:在页面load事件完成之后注册serviceWorker,(在load事件完成之后注册sw是为了避免进程阻塞)
  window.addEventListener('load', function(event) {
            if('serviceWorker' in window.navigator) {
            // {scope:'/'} 指的是在根目录的时候注册不写也是默认根目录
                navigator.serviceWorker.register('sw.js',{scope:'/'}).then(function(registeration){
                    console.log('service worker register success with scope', registeration.scope)
                })
                // 控制权发生改变,提醒用户数据更新了
                navigator.serviceWorker.oncontrollerchange = function(event) {
                    console.log('页面已经更新')
                    alert('页面已经更新')
                }
                
                // 兼容用户断网之后的情况
                
                 if(!navigator.onLine) {
                    alert('网络已经断开,内容可能已过期')
                    window.addEventListener('online',function(evnet) {
                        alert('网络已连接,刷新获取最新信息')
                    })
                }
            }
        })
调试工具中的功能介绍 application->serviceWorker
  • offline 指的是模拟浏览器断网的状态
  • updata to reload 每次都是重新安装注册sw
  • bypass for network 不经过sw的代理 只从网络请求中拿数据
  • 清除sw的缓存
    • clear storage->clear site data 直接一键清除sw的缓存数据
3:sw下配置 确定缓存的数据列表
let CACHE_VERSION = 0; //缓存版本号
let CACHE_NAME = 'cache_v' + CACHE_VERSION; // 缓存名称
let CACHE_URLS = [
    '/',
    '/api/movies',
    '/js/main.js',
    '/js/render.js',
    '/css/main.css',
    '/img/logo.png'
]

4:sw下配置 在什么时候去缓存这些数据
注意:

// 缓存的文件只要有一个失败所有都不能用

// sw文件会事先注册监听install文件

// 当sw注册成功之后install时间就会触发

function preCache() {
// 使用cache.openapi开辟和sw相对性的缓存区 存储在cache storage中
    return caches.open(CACHE_NAME)
        .then(function(cache) {
            return cache.addAll(CACHE_URLS)
        })
}
function clearCache() {
    return caches.keys().then(keys =>{
        keys.forEach(key => {
            // 如果key不等于当前的cachename就删除掉
            if(key !== CACHE_NAME) {
                caches.delete(key);
            }
        })
    })
}

function saveToCache (req, res) {
    return caches
        .open(CACHE_NAME)
        .then(cache => cache.put(req, res))
}

function fetchAndCache(req) {
    return fetch(req).then(function(res){
        // res 是一个流需要复制一份
        saveToCache(req, res.clone());
        return res;
    })
}
self.addEventListener("install", function(event) {
    event.waitUntil( // cache.open也是一个promise链,因此需要waitUntil事件来控制这个缓存阶段的流程
    
    // skipWaiting 让上一个serviceWorker返回
        preCache().then(self.skipWaiting)
    )
})
// 在activate触发时会删除旧的缓存
self.addEventListener('activate', function(event) {
    event.waitUntil(
        // 清除缓存同时获得控制权
        Promise.all([
            clearCache(),
            self.clients.claim()//在激活的过程里,需要调用clients.claim方法来让正在被激活的sw获得对cliam的完全控制权,
                                // 首次加载页面的时候 ,页面是没有被sw控制的,只有重新刷新页面才能不要重新刷新页面,就可是sw获得请求拦截等的页面控制权
        ])
    )
})

// fetch请求结束并且失败了才拿缓存中的数据
self.addEventListener('fetch', function(event) {
    let url = new URL(event.request.url);
    console.log('origin:' + origin,self.origin,'请求地址:'+event.request.url );// 如果不是同源数据就不拿sw的数据 走cnd拿数据
    if(url.origin !== self.origin) {
        return ;
    }
    // 处理缓存接口数据太旧的问题
    if(event.request.url.includes('/api/movies')) { 
        event.respondWith(
        //fetchAndCache :先请求网络数据,失败了才走缓存数据,有网的情况下请求保存到本地 如果失败了 拿缓存
            fetchAndCache(event.request).catch( 
            
                function() {
                    return caches.match(event.request);
                }
            )
        )
        return;
    }
    event.respondWith( //event.respondWith 等待其中的promise参数resolve之后才会内容给页面
        // 正常先从网络中请求数据,如果请求失败就从本地缓存中拿数据
        fetch(event.request).catch(function() {
            return caches.match(event.request);
        })
    )
})