Last active
October 14, 2015 19:09
-
-
Save wanderview/4f0f1bbf8d874842a920 to your computer and use it in GitHub Desktop.
PoC to extend service worker lifetime past end of fetch event by (ab)using postMessage()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head></head> | |
<body> | |
<script> | |
navigator.serviceWorker.addEventListener('message', function(evt) { | |
if (evt.data === 'CALL ME') { | |
navigator.serviceWorker.controller.postMessage('RING RING'); | |
} | |
}); | |
navigator.serviceWorker.register('sw.js'); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function doSlowWorker() { | |
// do something that takes a long time and return a promise | |
// that resolves when its done | |
return caches.open('big').then(function(cache) { cache.addAll(hugeList) }); | |
} | |
self.addEventListener('message', function(evt) { | |
if (evt.data === 'RING RING') { | |
evt.waitUntil(doSlowWork()); | |
} | |
}) | |
self.addEventListener('fetch', function(evt) { | |
evt.respondWith(Promise.all([ | |
fetch(evt.request), | |
self.clients.matchAll() | |
]).then(function(results) { | |
var response = results[0]; | |
var clientList = results[1]; | |
// We would do our slow work here, but we don't want to block the fetch | |
// evnt response and we can't safely do it past the end of .respondWith(). | |
// Instead, ask the document to postMessage() us so we can do the slow | |
// work in a separate .waitUntil(). This will not block the fetch | |
// event processing. | |
if (clientList.length > 0) { | |
clientList[0].postMessage('CALL ME'); | |
} | |
return response; | |
})); | |
}) |
Further correction, you cannot call evt.waitUntil()
after the original event handler has returned. So you have to do something like:
self.addEventListener('fetch', function(evt) {
evt.waitUntil(new Promise(function(resolveWaitUntil) {
evt.respondWith(fetch(evt.request).then(function(response) {
resolveWaitUntil(doSlowWork());
return response;
}));
}));
}));
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
So, it turns out neither Chrome nor Firefox implement .waitUntil() on the message event yet. So this won't work.
Also, the spec now include .waitUntil() on the FetchEvent directly. So this is preferred:
Of course, both chrome and firefox still need to implement FetchEvent.waitUntil().