Skip to content

Commit 58333a0

Browse files
committed
Merge pull request #40 from jeffposnick/sw-pass-through-caching
Pass-through caching demo.
2 parents 61cca7e + 20797cd commit 58333a0

File tree

3 files changed

+191
-0
lines changed

3 files changed

+191
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Service Worker Sample: Pass-through Caching
2+
===
3+
See https://googlechrome.github.io/samples/service-worker/pass-through-caching/index.html for a live demo.
4+
5+
Learn more at http://www.chromestatus.com/feature/6561526227927040
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<!doctype html>
2+
<!--
3+
Copyright 2014 Google Inc. All Rights Reserved.
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
-->
14+
<html lang="en">
15+
<head>
16+
<meta charset="utf-8">
17+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
18+
19+
<meta name="description" content="Sample of pass-through caching with Service Workers.">
20+
21+
<meta name="viewport" content="width=device-width, initial-scale=1">
22+
23+
<title>Service Worker Sample: Pass-through Caching</title>
24+
25+
<!-- Add to homescreen for Chrome on Android -->
26+
<meta name="mobile-web-app-capable" content="yes">
27+
<link rel="icon" sizes="192x192" href="../../images/touch/chrome-touch-icon-192x192.png">
28+
29+
<!-- Add to homescreen for Safari on iOS -->
30+
<!-- TODO: Replace PLACEHOLDER with feature name. -->
31+
<meta name="apple-mobile-web-app-title" content="Service Worker Sample: Pass-through Caching">
32+
33+
<meta name="apple-mobile-web-app-capable" content="yes">
34+
<meta name="apple-mobile-web-app-status-bar-style" content="black">
35+
<link rel="apple-touch-icon-precomposed" href="../../images/apple-touch-icon-precomposed.png">
36+
37+
<!-- Tile icon for Win8 (144x144 + tile color) -->
38+
<meta name="msapplication-TileImage" content="images/touch/ms-touch-icon-144x144-precomposed.png">
39+
<meta name="msapplication-TileColor" content="#3372DF">
40+
41+
<link rel="icon" href="../../images/favicon.ico">
42+
43+
<link rel="stylesheet" href="../../styles/main.css">
44+
</head>
45+
46+
<body>
47+
<h1>Service Worker Sample: Pass-through Caching</h1>
48+
49+
<p>Available in <a href="http://www.chromestatus.com/feature/6561526227927040">Chrome 40+</a></p>
50+
51+
<p>
52+
This sample demonstrates basic Service Worker registration, in conjunction with pass-through
53+
caching. After the Service Worker starts controlling this page, the first time a specific
54+
resource is requested, it's <code>fetch()</code>ed from the network and a copy of the response
55+
is stored in the Service Worker's cache. All subsequent times that the same resource is
56+
requested, it's returned directly from the cache.
57+
</p>
58+
59+
<p>
60+
<strong>Note:</strong> This is a very aggressive approach to caching, and might not be appropriate
61+
if your web application makes requests for arbitrary URLs as part of its normal operation
62+
(e.g. a RSS client or a news aggregator), as the cache could end up containing large responses
63+
that might not end up ever being accessed. Other approaches, like selectively caching based on
64+
response headers or only caching responses served from a specific domain, might be more
65+
appropriate for those use cases.
66+
</p>
67+
68+
<p>
69+
Visit <code>chrome://inspect/#service-workers</code> and click on the "inspect" link below
70+
the registered Service Worker to view logging statements for the various actions the
71+
<code><a href="service-worker.js">service-worker.js</a></code> script is performing.
72+
</p>
73+
74+
<!-- // [START code-block] -->
75+
<div class="output">
76+
<div id="status"></div>
77+
78+
<ul id="images" style="display: none">
79+
<li><img src="http://www.chromium.org/_/rsrc/1302286216006/config/customLogo.gif"></li>
80+
<li><img src="http://www.chromium.org/_/rsrc/1365117468642/chromium-projects/chrome-64.png"></li>
81+
</ul>
82+
</div>
83+
84+
<script>
85+
function showImages() {
86+
document.querySelector('#images').style.display = 'block';
87+
}
88+
89+
if ('serviceWorker' in navigator) {
90+
navigator.serviceWorker.register('./service-worker.js', {scope: './'}).then(
91+
function() {
92+
// Registration was successful. Now, check to see whether the Service Worker is controlling the page.
93+
if (navigator.serviceWorker.controller) {
94+
// If .controller is set, then this page is being actively controlled by the Service Worker.
95+
document.querySelector('#status').textContent = 'The Service Worker is currently handling network operations. ' +
96+
'If you reload the page, the images (and everything else) will be served from the Service Worker\'s cache.';
97+
98+
showImages();
99+
} else {
100+
// If .controller isn't set, then prompt the user to reload the page so that the Service Worker can take
101+
// control. Until that happens, the Service Worker's fetch handler won't be used.
102+
document.querySelector('#status').textContent = 'Please reload this page to allow the Service Worker to handle network operations.';
103+
}
104+
},
105+
function(error) {
106+
// Something went wrong during registration. The service-worker.js file
107+
// might be unavailable or contain a syntax error.
108+
document.querySelector('#status').textContent = error;
109+
}
110+
);
111+
} else {
112+
// The current browser doesn't support Service Workers.
113+
var aElement = document.createElement('a');
114+
aElement.href = 'http://www.chromium.org/blink/serviceworker/service-worker-faq';
115+
aElement.textContent = 'Service Workers are not supported in the current browser.';
116+
document.querySelector('#status').appendChild(aElement);
117+
}
118+
</script>
119+
<!-- // [END code-block] -->
120+
121+
<script>
122+
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
123+
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
124+
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
125+
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
126+
ga('create', 'UA-53563471-1', 'auto');
127+
ga('send', 'pageview');
128+
</script>
129+
<!-- Built with love using Web Starter Kit -->
130+
</body>
131+
</html>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// This sample illustrates an aggressive approach to caching, in which every valid response is
2+
// cached and every request is first checked against the cache.
3+
// This may not be an appropriate approach if your web application makes requests for
4+
// arbitrary URLs as part of its normal operation (e.g. a RSS client or a news aggregator),
5+
// as the cache could end up containing large responses that might not end up ever being accessed.
6+
// Other approaches, like selectively caching based on response headers or only caching
7+
// responses served from a specific domain, might be more appropriate for those use cases.
8+
9+
self.addEventListener('fetch', function(event) {
10+
console.log('Handling fetch event for', event.request.url);
11+
12+
event.respondWith(
13+
caches.open('pass-through-caching-sample').then(function(cache) {
14+
return cache.match(event.request).then(function(response) {
15+
if (response) {
16+
// If there is an entry in the cache for event.request, then response will be defined
17+
// and we can just return it.
18+
console.log(' Found response in cache:', response);
19+
20+
return response;
21+
} else {
22+
// Otherwise, if there is no entry in the cache for event.request, response will be
23+
// undefined, and we need to fetch() the resource.
24+
console.log(' No response for %s found in cache. About to fetch from network...', event.request.url);
25+
26+
return fetch(event.request.clone()).then(function(response) {
27+
console.log(' Response for %s from network is: %O', event.request.url, response);
28+
29+
if (response && response.status < 400) {
30+
// This avoids caching responses that we know are errors (i.e. HTTP status code of 4xx or 5xx).
31+
// One limitation is that, for non-CORS requests, we get back a filtered opaque response
32+
// (https://fetch.spec.whatwg.org/#concept-filtered-response-opaque) which will always have a
33+
// .status of 0, regardless of whether the underlying HTTP call was successful. Since we're
34+
// blindly caching those opaque responses, we run the risk of caching a transient error response.
35+
//
36+
// We need to call .clone() on the response object to save a copy of it to the cache.
37+
// (https://fetch.spec.whatwg.org/#dom-request-clone)
38+
cache.put(event.request, response.clone());
39+
}
40+
41+
// Return the original response object, which will be used to fulfill the resource request.
42+
return response;
43+
});
44+
}
45+
}).catch(function(error) {
46+
// This catch() will handle exceptions that arise from the match() or fetch() operations.
47+
// Note that a HTTP error response (e.g. 404) will NOT trigger an exception.
48+
// It will return a normal response object that has the appropriate error code set.
49+
console.error(' Pass-through caching failed:', error);
50+
51+
throw error;
52+
});
53+
})
54+
);
55+
});

0 commit comments

Comments
 (0)