我正在开发具有所有功能(如离线,添加到主屏幕,通知等)的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)方法,服务工作者应该从网络获取图像,对吧? 代码的结果显示在下图中。
如果我试图“逼”,我想有明确要求的浏览器更新加载图像(https://mywebsite.com/service/images/demo.jpg)服务人员正确地获取请求,但始终显示旧图像。 我认为我在做一些愚蠢的错误,但我不明白是什么。
有几种方法可以处理静态文件缓存。你可以在你的web服务器(nginx)或webpack(javascript应用程序的模块打包器)中处理它 – codemax
你认为哪种方法可以做到这一点?现在我看到了sw-precache。也许它可以做我想做的事情,因为它会对每个文件做一个散列来捕捉新版本(如果存在)(对吧?) – diegocom
我在我的项目中使用了react js,它和webpack很好地搭配。 Webpack有一个名为“加载器”的概念,它为你预处理静态文件。您可以查看文档以更好地理解它。 https://webpack.js.org/loaders/html-loader/ – codemax