0

我正在开发具有所有功能(如离线,添加到主屏幕,通知等)的PWA,但是当我尝试刷新UI时遇到了一些问题。渐进式Web应用程序和缓存UI

换句话说,我有我的PWA与index.html文件中定义的用户界面,我想要做的是缓存PWA离线使用它(我能够做到这一点),如果设备在线检查UI是否有更新(在index.html文件中,或者在它所依赖的文件中),下载这些更改并刷新设备上和缓存中的UI。

随着数据我没有任何问题与缓存。

例如,如果我有这个页面index.html

<!DOCTYPE html> 
<html> 
<head > 
    <meta charset="utf-8"> 
    <meta http-equiv="X-UA-Compatible" content="IE=edge"> 
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
    <title class="title">PWA</title> 

    <link rel="manifest" href="manifest.json"> 

    <meta name="mobile-web-app-capable" content="yes"> 
    <meta name="apple-mobile-web-app-capable" content="yes"> 
    <meta name="apple-mobile-web-app-status-bar-style" content="black"> 
    <meta name="apple-mobile-web-app-title" content="PWA"> 
    <link rel="apple-touch-icon" href="imgs/icons/Icon-152.png"> 
    <meta name="msapplication-TileImage" content="imgs/icons/Icon-144.png"> 
    <meta name="msapplication-TileColor" content="#2F3BA2"> 
    <link rel="shortcut icon" sizes="32x32" href="imgs/icons/Icon-32.png"> 
    <link rel="shortcut icon" sizes="196x196" href="imgs/icons/Icon-196.png"> 
    <link rel="apple-touch-icon-precomposed" href="imgs/icons/Icon-152.png"> 
    </head> 

<body> 

<div class="container"> 
    <div class="row"> 
     <div class="col-12"> 
      <img src="imgs/images.png"> 
     </div> 
    </div> 
</div> 

<script src="js/jquery.js"></script> 
<script src="js/bootstrap.js"></script> 
<script src="js/app.js"></script> 
</body> 
</html> 

app.js

if('serviceWorker' in navigator) { 
    navigator.serviceWorker 
      .register('service-worker.js') 
      .then(function() { console.log('Service Worker Registered'); }); 
    } 

service-worker.js

var dataCacheName = 'dataCache-v2'; 
var cacheName = 'cache-v2'; 
var filesToCache = [ 
    'index.html', 
    'imgs/images.png', 
    'src/app.js' 
]; 

self.addEventListener('install', function(e) { 
    console.log('[ServiceWorker] Install'); 
    e.waitUntil(
    caches.open(cacheName).then(function(cache) { 
     console.log('[ServiceWorker] Caching App Shell'); 
     return cache.addAll(filesToCache); 
    }) 
); 
}); 

self.addEventListener('activate', function(e) { 
    console.log('[ServiceWorker] Activate'); 
    e.waitUntil(
    caches.keys().then(function(keyList) { 
     return Promise.all(keyList.map(function(key) { 
     console.log('[ServiceWorker] Removing old cache', key); 
     if (key !== cacheName && key !== dataCacheName) { 
      return caches.delete(key); 
     } 
     })); 
    }) 
); 
return self.clients.claim(); 
}); 

self.addEventListener('fetch', function(e) { 
    console.log('[ServiceWorker] Fetch', e.request.url); 
    var dataUrl = 'URL-WHERE-FIND-DATA'; 
    if (e.request.url.indexOf(dataUrl) === 0) { 
    e.respondWith(
     fetch(e.request) 
     .then(function(response) { 
      return caches.open(dataCacheName).then(function(cache) { 
      cache.put(e.request.url, response.clone()); 
      console.log('[ServiceWorker] Fetched&Cached Data'); 
      return response; 
      }); 
     }) 
    ); 
    } else { 
    e.respondWith(
     caches.match(e.request).then(function(response) { 
     return response || fetch(e.request); 
     }) 
    ); 
    } 
}); 

假设我与另一个形象,但与更换images.png同名,我怎么笑新的一个给用户? 如果我刷新页面,数据从网络中获取(如果可用),但图像仍然从缓存中捕获。

我希望我已经很好地解释了我的问题。非常感谢大家,这将有助于我

更新#1:

我试图实现“高速缓存,然后网络”战略,阿内尔平衡到达向我建议,但问题是一直在这里,浏览器总是显示缓存的图像(在下面的代码中,我尝试更新名为'demo.jpg'的图像)。 也许我做错了什么。 这是我的代码:

service-worker.js

self.addEventListener('fetch', function(event) { 
     event.respondWith(
    caches.open("my-cache").then(function(cache) { 
     return fetch(event.request).then(function(response) { 
      console.log('Fetch: ' + response.url); 
     cache.put(event.request, response.clone()); 
     return response; 
     }); 
    }) 
); 
}); 

app.js

var networkDataReceived = false; 


var networkUpdate = fetch('https://website.com/app/images/demo.jpg').then(function(response) { 
    return response.blob(); 
}).then(function(data) { 
    networkDataReceived = true; 
    updatePage(data); 
}); 

caches.match('https://website.com/app/images/demo.jpg').then(function(response) { 
    if (!response) throw Error("No data"); 
    return response.blob(); 
}).then(function(data) { 
    if (!networkDataReceived) { 
    updatePage(data); 
    } 
}).catch(function() { 
    return networkUpdate; 
}).catch(showErrorMessage); 


function showErrorMessage(response){ 
    console.log("Error: " + response); 
} 

function updatePage(response) { 
    var img = document.getElementById('demo'); 
    var imageUrl = URL.createObjectURL(response); 
    img.src = imageUrl; 
} 

任何新的建议?由于

更新#2:

现在我想要做的一切从头开始。 我从这个谷歌的例子复制服务工作者:https://developers.google.com/web/fundamentals/getting-started/codelabs/your-first-pwapp/ 这实现了“缓存然后网络”策略。 的service-worker.js的代码是这样的:

var dataCacheName = 'dataCache1'; 
var cacheName = 'cache1'; 

var filesToCache = [ 
    '/', 
    'index.html', 
    'css/main.css', 
    'src/app.js' 
]; 

self.addEventListener('install', function(e) { 
    console.log('[ServiceWorker] Install'); 
    e.waitUntil(
     caches.open(cacheName).then(function(cache) { 
      console.log('[ServiceWorker] Caching app shell'); 
      return cache.addAll(filesToCache); 
     }) 
    ); 
}); 

self.addEventListener('activate', function(e) { 
    console.log('[ServiceWorker] Activate'); 
    e.waitUntil(
     caches.keys().then(function(keyList) { 
      return Promise.all(keyList.map(function(key) { 
       if (key !== cacheName && key !== dataCacheName) { 
        console.log('[ServiceWorker] Removing old cache', key); 
        return caches.delete(key); 
       } 
      })); 
     }) 
    ); 
    /* 
    * Fixes a corner case in which the app wasn't returning the latest data. 
    * You can reproduce the corner case by commenting out the line below and 
    * then doing the following steps: 1) load app for first time so that the 
    * initial New York City data is shown 2) press the refresh button on the 
    * app 3) go offline 4) reload the app. You expect to see the newer NYC 
    * data, but you actually see the initial data. This happens because the 
    * service worker is not yet activated. The code below essentially lets 
    * you activate the service worker faster. 
    */ 
    return self.clients.claim(); 
}); 

self.addEventListener('fetch', function(e) { 
    console.log('[Service Worker] Fetch', e.request.url); 
    var dataUrl = 'https:/mywebsite.it/service/images/demo.jpg'; 
    if (e.request.url.indexOf(dataUrl) > -1) { 
     /* 
     * When the request URL contains dataUrl, the app is asking for fresh 
     * weather data. In this case, the service worker always goes to the 
     * network and then caches the response. This is called the "Cache then 
     * network" strategy: 
     * https://jakearchibald.com/2014/offline-cookbook/#cache-then-network 
     */ 
     e.respondWith(
      caches.open(dataCacheName).then(function(cache) { 
       return fetch(e.request).then(function(response){ 
        cache.put(e.request.url, response.clone()); 
        return response; 
       }); 
      }) 
     ); 
    } else { 
     /* 
     * The app is asking for app shell files. In this scenario the app uses the 
     * "Cache, falling back to the network" offline strategy: 
     * https://jakearchibald.com/2014/offline-cookbook/#cache-falling-back-to-network 
     */ 
     e.respondWith(
      caches.match(e.request).then(function(response) { 
       return response || fetch(e.request); 
      }) 
     ); 
    } 
}); 

而结果总是相同的,图像不会得到更新。 使用获取(url)方法,服务工作者应该从网络获取图像,对吧? 代码的结果显示在下图中。

当我重新加载页面的唯一获取请求的文件夹“/服务/” Main request

如果我试图“逼”,我想有明确要求的浏览器更新加载图像(https://mywebsite.com/service/images/demo.jpg)服务人员正确地获取请求,但始终显示旧图像。 forced request 我认为我在做一些愚蠢的错误,但我不明白是什么。

+0

有几种方法可以处理静态文件缓存。你可以在你的web服务器(nginx)或webpack(javascript应用程序的模块打包器)中处理它 – codemax

+0

你认为哪种方法可以做到这一点?现在我看到了sw-precache。也许它可以做我想做的事情,因为它会对每个文件做一个散列来捕捉新版本(如果存在)(对吧?) – diegocom

+0

我在我的项目中使用了react js,它和webpack很好地搭配。 Webpack有一个名为“加载器”的概念,它为你预处理静态文件。您可以查看文档以更好地理解它。 https://webpack.js.org/loaders/html-loader/ – codemax

回答

1

为什么图像被从缓存中提供的原因是因为这是对服务人员进行编码做:

e.respondWith(
    caches.match(e.request).then(function(response) { 
    return response || fetch(e.request); 
    }) 
); 

这首先检查你的缓存如果请求的响应已经存储,并如果没有,只从网络获取资源。

当我看到它,你必须处理这两种可能的途径:

  1. 确保资源(包括图片)变化的文件名时的该资源变化的实际内容。有几个构建工具可以通过将资源的哈希附加到文件名中来为您做这件事。资源内容的更改会导致不同的散列,因此会生成不同的文件名。

  2. 您可以使用则缓存网络由杰克·阿奇博尔德在this article描述策略。这个想法是,如果缓存的资源可用,则为其提供服务,同时通过网络请求该资源。一旦网络请求完成,您就可以使用从网络获取的内容替换先前提供的内容,并更新缓存的资源版本。这样,您可以确定用户正在查看资源的最新版本,但仍未通过更新该资源的缓存版本来破坏脱机体验。

+0

我已阅读您在第二种方法(缓存然后网络)中向我推荐的文章,但图像的问题仍然存在。 我刚刚更新了我的问题与我的问题 – diegocom

相关问题