How can I cache network data in service worker? - caching

I have created Progressive Web Application (PWA) with angular 5.0 and .net core 2.0. It works fine in offline mode. But only static data are cached for offline mode. I need to store previously requested network data in service worker cache, so that I can fetch these data through service worker cache in offline mode.

You can use also angular service worker for it.
Data Groups - Cache External API Data
The data groups config allows you to cache external API calls, which makes it possible for your app to use an external data source without a network connection. This data is not known at build-time, so it can only be cached at runtime. There are two possible strategies for caching data sources - freshness and performance.
api-freshness - This freshness strategy will attempt to serve data from the network first, then fallback to th cache. You can set a maxAge property that defines how long to cache responses and a timeout that defines how long to wait before falling back to the cache.
api-performance - The performance cache will serve data from the cache first and only reach out to the network if the cache is expired.
Example you could find here in section ngsw-config.json.

Try to check HTTP Caching.
All you need to do is ensure that each server response provides the
correct HTTP header directives to instruct the browser on when and for
how long the browser can cache the response.
For further info, you can check the whole documentation. It provides example and illustrations to understand better about HTTP Caching.

Related

The difference between browser cache and ServiceWorker cache

I do not understand the difference between browser cache and ServiceWorker cache.
For example, in browser cache, set the expiration cache for all resources. In this way, the HEAD should not verify within the time limit. In other words, you should be able to acquire resources in an offline state because you do not query the server.
On the other hand, if you set cache priority in ServiceWorker, you can acquire resources in the offline state after the second time.
"Both browser cache and ServiceWorker cache can get resources in the offline state"
Is it good to understand that?
I think by "browser cache" you mean the http cache. This is an opportunistic cache of responses across the entire browser. (Mostly, that is. In some browsers its isolated by the top level tab origin.) The browser can evict responses from http cache at any time. It makes no guarantees that data will be present in the http cache at any time. Generally, though, it uses an LRU-based heuristic to age older unused data out. Sites can influence what is stored in http cache using cache-control headers.
In contrast, the Cache API used in service workers is more like IndexedDB. While it stores responses just like http cache it differs in that the site is fully in control. There is an explicitly API for storing and retrieving data. The browser guarantees Cache API data will not be deleted unless the site does it themselves or the entire origin is evicted via the quota mechanism. The Cache API is also much more precisely specified in terms of its behavior compared to http cache. The only way to use the Cache API data during loading, though, is via a ServiceWorker that matches a request using Cache API and then returns the Response to the FetchEvent.respondWith().
Note a ServiceWorker can end up interacting with both of these systems. It can explicitly use the Cache API. It can also pull from http cache when it calls fetch().

From a purely caching point of view, is there any advantage using the new Cache API instead of regular http cache?

The arrival of service workers has led to a great number of improvements to the web. There are many use cases for service workers.
However, from a purely caching point of view, does it makes sense to use the Cache API?
Many approaches make assumptions of how resources will be handled.
Often only the URL is used to determine how the resource should be handled with strategies such as Network first, Network Only, Stale-while-revalidate, Cache first and Cache only. This can be tedious work, because you have to define a specific handler for many URLs. It's not scalable.
Instead I was thinking of using regular HTTP cache in combination with the Cache API. Response headers contain useful information that can be used to cache and verify if the cache can still be used or if a new version would be available. Together with best practice caching (for example https://jakearchibald.com/2016/caching-best-practices/), this could create a generic service worker that has not te be updated when resources change.
Based on the response headers, a resource could be handled by a custom handler. If the headers would ever be updated, it would be possible to handle the resource with a different handler if necessary.
But then I realised, I was just reimplementing browser cache with the Cache API. This would mean that the resources would be cached double (take this with a grain of salt), by storing it in both the browser and the service worker cache. Additionally, while the Cache API provides more control, most handlers can be (sort of) simulated with http cache:
Network only: Cache-Control: no-store
Cache only: Cache-Control: immutable
Cache first: Cache-Control: max-age with validation (Etag, Last Modified, ...)
Stale-while-revalidate: Cache-Control: stale-while-revalidate
I don't immediately see how to simulate network first, but then again this would imply support for offline usage (or bad connection). (Keep in mind, this is not the use case I'm looking for).
While it's always useful to provide a fallback (using service workers & Cache API), is it worth having the resources possibly cached double and having copied the browser's caching logic? I'm aware that the Cache API can be used to precache resources, but I think these could also be precached by requesting them in advance.
Lastly, I know the browser is in charge of managing the browser cache and a developer has limited control over it (using HTTP Cache headers).
But the browser could also choose to remove the whole service worker cache to clear disk space. There are ways to make sure the cache persists, but that's not the point here.
My questions are:
What advantages has the Cache API that can't be simulated with regular browser cache?
What could be cached with the Cache API, but not with regular browser cache?
Is there another way to create a service worker that does not need to be updated
What advantages has the Cache API that can't be simulated with regular browser cache?
CacheAPI have been created to be manipulated by Service Worker, so you can do nearly what you want with it, be you can't interfere or do anything to HTTP cache, it's all in browser mechanic, i'm not sure but HTTP cache is completly wreck when your offline, not CacheAPI.
What could be cached with the Cache API, but not with regular browser cache?
Before caching request, you can alter request to fit your need, or even cache response with Cache-Control: 0 if you want. Even store custom data that will need after.
Is there another way to create a service worker that does not need to be updated
It need a bit of work, be two of solution to achieve that is :
On each page call you communicate with SW using postMessage to compare version (it can be an id, a hash or even whole list of assets), it's different, you can load list of ressource from given location then add it to cache. (Due to javascript use, this won't work if you have to make it work from AMP)
Each time a user load a page, or each 10/20min ( or both, whatever you want ), you call a files to know your assert version, if it's different, you do the same thing on the other solution.
Hope I help

google workbox webpack plugin to fetch from cache first before service worker

When I just use pre-cache from Workbox Plugin, the service worker try to fetch from indexdb instead of cache(browser-cache).
Yes, service worker is faster than fetching from server. However, if it fetches from memory it takes 0 second.
I have seen all the strategies from workbox but it does not have a strategy that try to fetch from memory first.
This is everything for pre-cache.
new WorkboxPlugin.GenerateSW({
skipWaiting: true,
importWorkboxFrom: 'local',
})
service-worker.js
importScripts("/dist/workbox-v3.6.3/workbox-sw.js");
workbox.setConfig({modulePathPrefix: "/dist/workbox-v3.6.3"});
importScripts(
"/dist/precache-manifest.4b8be844a396ff2fc7335cebbab35f10.js"
);
workbox.skipWaiting();
/**
* The workboxSW.precacheAndRoute() method efficiently caches and responds to
* requests for URLs in the manifest.
*/
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
You can't control how the request is served by the browser cache or the server, so you can't unfortunately first try browser cache, then Cache API, then server.
However, you can try to load both from Cache API and server (including browser cache) at the same time, and serve whichever gave an the fastest answer.
That's what Jake Archibald named "Cache & network race" in his Offline Cookbook: https://jakearchibald.com/2014/offline-cookbook/#cache-network-race
Just to clarify - Workbox tracks a hash of the files in indexedDB, but it doesn't use indexedDB to serve the file. It uses the Cache API to store and retrieve the files.
In your question you mix, Cache, memory, and service worker in terms of where a response is coming from. So to clarify that a little bit:
If you have a service worker registered for a page (i.e. the service worker controls the page), then all network requests will first go to the service worker.
The service worker can either come up with a response by any means, or it can go to the network (see service worker response section).
Once it goes to the network, the browser can decide where it gets its response (see browser response section).
Service Worker Response
The service worker will generally do one of three things to create a response:
Use a response from the Cache API to return.
Get a response from the network and return it (possibly adding it to the cache).
Generate a custom response using any number of sources including static strings, streams, Cache API responses and network responses.
Notice in this list I refer to the Cache API. This is a response cached by a web app that is stored on the users machines.
Browser Response
For any network responses the browser can do one of the following to get a response:
Go to the network and get a new response from the server
Reference the HTTP cache to return a response
The HTTP cache is separate from the Cache API. It's out of a developers control and can't be relied upon. The browser does what it feels is best.
Workbox + Service Worker
Workbox provides a set of utilities to make the "Service Worker Response" part easier to work with and develop for. This means it's only dealing with the three response types I've outlined.
I've noted down what workbox precaching does and how it works, including what indexedDB is used for in precaching: https://developers.google.com/web/tools/workbox/modules/workbox-precaching

Falcor: avoid outdated client cache

I'm considering to use Falcor in an app project I'm currently working on, I've started reading the docs but there's still one issue that is not entirely clear to me.
Let's make this example.
At time zero client A performs a request to a Falcor model, which in turns retrieves the needed data from a server DataSource, and stores it in the client's cache.
At time one the same server data is changed by operations performed by client B.
At time two client A performs the same request to the Falcor model, which finds a cached value and serves the now outdated data.
Is there any way to notifiy client A after time one that its Falcor cache for that data is outdated, and should instead perform a new request to the server DataSource?
You can use web sockets to send messages to the client. On the client you can call invalidate to manually invalidate the cache. You can also set an expires time on values to cause them to expire after a certain amount of time.

WebApi - Redis cache vs Output cache

I have been studying about Redis (no experience at all - just studied theory), and after doing some research, found out that its also being used as cache. e.g. StackOverfolow it self.
My question is, if I have an asp.net WebApi service, and I use output caching at the WebApi level to cache responses, I am basically storing kind of key/value (request/response) in server's memory to deliver cached responses.
Now as redis is an in memory database, how will it help me to substitute WebApi's output caching with redis cache?
Is there any advantage?
I tried to go through this answer redis-cache-vs-using-memory-directyly, but I guess I didn't got the key line in the answer:
"Basically, if you need your application to scale on several nodes sharing the same data, then something like Redis (or any other remote key/value store) will be required."
I am basically storing kind of key/value (request/response) in server's memory to deliver cached responses.
This means that after a server restart, the server will have to rebuild the cache . That won't be the case with Redis. So one advantage of Redis over a homemade in-memory solution is persistence (only if that's an issue for you and that you did not planned to write persistence yourself).
Then instead of coding your own expiring mechanism, you can use Redis EXPIRE or command EXPIREAT or even simply specifying the expire timestamp when putting the api output string into cache with SETEX.
if you need your application to scale on several nodes sharing the same data
What it means is that if you have multiple instances of the same api servers, putting the cache into redis will allow these servers to share the same cache, thus reducing, for instance, memory consumption (1 cache instead of 3 in-memory cache), and so on...

Resources