Guida per principianti all'utilizzo della cache delle applicazioni

Introduzione

Sta diventando sempre più importante per l'accessibilità offline delle applicazioni basate sul web. Sì, tutti i browser possono memorizzare nella cache pagine e risorse per lunghi periodi, se richiesto, ma il browser può espellere singoli elementi dalla cache in qualsiasi momento per fare spazio ad altre cose. Grazie all'interfaccia ApplicationCache, HTML5 risolve alcuni dei seccature legate alla modalità offline. L'utilizzo dell'interfaccia cache offre all'applicazione tre vantaggi:

  1. Navigazione offline: gli utenti possono navigare nell'intero sito quando sono offline
  2. Velocità: le risorse provengono direttamente dal disco, senza alcun viaggio nella rete.
  3. Resilienza: se il tuo sito non funziona per "manutenzione" (ad esempio se qualcuno rompe per errore tutto), gli utenti godranno dell'esperienza offline

La cache dell'applicazione (o AppCache) consente a uno sviluppatore di specificare i file che il browser deve memorizzare nella cache e rendere disponibili agli utenti offline. L'app verrà caricata e funzionerà correttamente, anche se l'utente preme il pulsante di aggiornamento mentre è offline.

Il file manifest della cache

Il file manifest della cache è un semplice file di testo che elenca le risorse che il browser deve memorizzare nella cache per l'accesso offline.

Fare riferimento a un file manifest

Per attivare la cache dell'applicazione per un'app, includi l'attributo manifest nel tag html del documento:

<html manifest="example.appcache">
  ...
</html>

L'attributo manifest deve essere incluso in ogni pagina dell'applicazione web che vuoi memorizzare nella cache. Il browser non memorizza nella cache una pagina se non contiene l'attributo manifest (a meno che non sia elencata esplicitamente nel file manifest stesso. Ciò significa che ogni pagina visitata dall'utente che include un manifest verrà implicitamente aggiunta alla cache dell'applicazione. Pertanto, non è necessario elencare ogni pagina nel file manifest. Se una pagina rimanda a un file manifest, non è possibile impedire che la pagina venga memorizzata nella cache.

Puoi visualizzare gli URL controllati dalla cache dell'applicazione visitando la pagina about://appcache-internals/ in Chrome. Da qui puoi svuotare le cache e visualizzare le voci. In Firefox sono disponibili strumenti per sviluppatori simili.

L'attributo manifest può indirizzare a un URL assoluto o a un percorso relativo, ma quest'ultimo deve trovarsi nella stessa origine dell'applicazione web. Un file manifest può avere qualsiasi estensione, ma deve essere pubblicato con il tipo MIME corretto (vedi di seguito).

<html manifest="http://www.example.com/example.mf">
  ...
</html>

Deve essere pubblicato un file manifest con il tipo MIME text/cache-manifest. Potresti dover aggiungere un tipo di file personalizzato al server web o alla configurazione .htaccess.

Ad esempio, per pubblicare questo tipo MIME in Apache, aggiungi questa riga al file di configurazione:

AddType text/cache-manifest .appcache

Oppure, nel file app.yaml in Google App Engine:

- url: /mystaticdir/(.*\.appcache)
  static_files: mystaticdir/\1
  mime_type: text/cache-manifest
  upload: mystaticdir/(.*\.appcache)

Questo requisito è stato eliminato dalla specifica tempo fa e non è più richiesto dalle versioni più recenti di Chrome, Safari e Firefox, ma avrai bisogno del tipo MIME per funzionare nei browser meno recenti e in IE11.

Struttura di un file manifest

Il file manifest è un file separato a cui ti colleghi tramite l'attributo manifest nell'elemento html. Un file manifest semplice ha un aspetto simile al seguente:

CACHE MANIFEST
index.html
stylesheet.css
images/logo.png
scripts/main.js
http://cdn.example.com/scripts/main.js

In questo esempio verranno memorizzati nella cache quattro file della pagina che specifica il file manifest.

Ci sono un paio di aspetti da considerare:

  • La stringa CACHE MANIFEST è la prima riga ed è obbligatoria.
  • I file possono provenire da un altro dominio
  • Alcuni browser impongono limitazioni alla quantità di spazio di archiviazione disponibile per la tua app. In Chrome, ad esempio, AppCache utilizza un pool condiviso di spazio di archiviazione TEMPORANEO che le altre API offline possono condividere. Se stai scrivendo un'app per il Chrome Web Store, l'utilizzo di unlimitedStorage rimuove questa restrizione.
  • Se il manifest restituisce un errore 404 o 410, la cache viene eliminata.
  • Se non riesce a scaricare il manifest o una risorsa specificata, l'intero processo di aggiornamento della cache non riesce. In caso di errore, il browser continuerà a utilizzare la cache dell'applicazione precedente.

Diamo un'occhiata a un esempio più complesso:

CACHE MANIFEST
# 2010-06-18:v2

# Explicitly cached 'master entries'.
CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js

# Resources that require the user to be online.
NETWORK:
*

# static.html will be served if main.py is inaccessible
# offline.jpg will be served in place of all images in images/large/
# offline.html will be served in place of all other .html files
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg

Le righe che iniziano con "#" sono righe di commento, ma possono anche servire per un altro scopo. La cache di un'applicazione viene aggiornata solo quando il relativo file manifest cambia. Ad esempio, se modifichi una risorsa immagine o cambi una funzione JavaScript, le modifiche non verranno memorizzate nuovamente nella cache. Devi modificare il file manifest stesso per comunicare al browser di aggiornare i file memorizzati nella cache.

Evita di utilizzare timestamp che si aggiornano continuamente o stringhe casuali per forzare gli aggiornamenti ogni volta. Il file manifest viene controllato due volte durante un aggiornamento, una all'inizio e una dopo che tutti i file memorizzati nella cache sono stati aggiornati. Se il file manifest è cambiato durante l'aggiornamento, è possibile che il browser abbia recuperato alcuni file da una versione e altri file da un'altra versione. In questo modo non applica la cache e riprova in un secondo momento.

Sebbene la cache si aggiorni, il browser non utilizza questi file fino a quando la pagina non viene aggiornata, perché questo avviene dopo che la pagina è stata caricata dalla versione corrente della cache.

Un file manifest può avere tre sezioni distinte: CACHE, NETWORK e FALLBACK.

CACHE:
Questa è la sezione predefinita per le voci. I file elencati sotto questa intestazione (o subito dopo CACHE MANIFEST) verranno esplicitamente memorizzati nella cache dopo il primo download. NETWORK:
I file elencati in questa sezione potrebbero provenire dalla rete se non sono nella cache, altrimenti la rete non viene utilizzata, anche se l'utente è online. Puoi inserire URL specifici nella lista consentita qui o semplicemente "", che consente tutti gli URL. La maggior parte dei siti deve avere il valore "". FALLBACK:
Una sezione facoltativa che specifica le pagine di riserva se una risorsa non è accessibile. Il primo URI è la risorsa, il secondo è quello di riserva utilizzato se la richiesta di rete non riesce o presenta errori. Entrambi gli URI devono avere la stessa origine del file manifest. Puoi acquisire URL specifici, ma anche prefissi di URL. "images/large/" acquisirà errori da URL quali "images/large/whatever/img.jpg".

Il seguente manifest definisce una pagina "catch-all" (offline.html) che verrà visualizzata quando l'utente tenterà di accedere alla directory principale del sito in modalità offline. Dichiara inoltre che tutte le altre risorse (ad es. quelle su un sito remoto) richiedono una connessione a internet.

CACHE MANIFEST
# 2010-06-18:v3

# Explicitly cached entries
index.html
css/style.css

# offline.html will be displayed if the user is offline
FALLBACK:
/ /offline.html

# All other resources (e.g. sites) require the user to be online.
NETWORK:
*

# Additional resources to cache
CACHE:
images/logo1.png
images/logo2.png
images/logo3.png

Aggiornamento della cache

Quando un'applicazione è offline, rimane memorizzata nella cache fino a quando non si verifica una delle seguenti condizioni:

  1. L'utente cancella i dati memorizzati nel browser per il tuo sito.
  2. Il file manifest è stato modificato. Nota: l'aggiornamento di un file elencato nel manifest non significa che il browser memorizzerà nuovamente la risorsa nella cache. Il file manifest deve essere modificato.

Stato della cache

L'oggetto window.applicationCache è l'accesso programmatico alla cache delle app del browser. La sua proprietà status è utile per controllare lo stato attuale della cache:

var appCache = window.applicationCache;

switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
case appCache.CHECKING: // CHECKING == 2
return 'CHECKING';
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3
return 'DOWNLOADING';
break;
case appCache.UPDATEREADY:  // UPDATEREADY == 4
return 'UPDATEREADY';
break;
case appCache.OBSOLETE: // OBSOLETE == 5
return 'OBSOLETE';
break;
default:
return 'UKNOWN CACHE STATUS';
break;
};

Per verificare in modo programmatico la disponibilità di aggiornamenti del manifest, chiama prima applicationCache.update(). Questa operazione tenterà di aggiornare la cache dell'utente (il che richiede la modifica del file manifest). Infine, quando applicationCache.status è nello stato UPDATEREADY, la chiamata a applicationCache.swapCache() sostituirà la vecchia cache con quella nuova.

var appCache = window.applicationCache;

appCache.update(); // Attempt to update the user's cache.

...

if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache();  // The fetch was successful, swap in the new cache.
}

La buona notizia è che puoi automatizzare questa operazione. Per aggiornare gli utenti alla versione più recente del sito, imposta un listener per monitorare l'evento updateready al caricamento della pagina:

// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {

window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
    // Browser downloaded a new app cache.
    if (confirm('A new version of this site is available. Load it?')) {
    window.location.reload();
    }
} else {
    // Manifest didn't changed. Nothing new to server.
}
}, false);

}, false);

Eventi AppCache

Come previsto, vengono esposti eventi aggiuntivi per monitorare lo stato della cache. Il browser attiva gli eventi, ad esempio, per l'avanzamento del download, l'aggiornamento della cache dell'app e le condizioni di errore. Lo snippet seguente imposta i listener di eventi per ogni tipo di evento della cache:

function handleCacheEvent(e) {
//...
}

function handleCacheError(e) {
alert('Error: Cache failed to update!');
};

// Fired after the first cache of the manifest.
appCache.addEventListener('cached', handleCacheEvent, false);

// Checking for an update. Always the first event fired in the sequence.
appCache.addEventListener('checking', handleCacheEvent, false);

// An update was found. The browser is fetching resources.
appCache.addEventListener('downloading', handleCacheEvent, false);

// The manifest returns 404 or 410, the download failed,
// or the manifest changed while the download was in progress.
appCache.addEventListener('error', handleCacheError, false);

// Fired after the first download of the manifest.
appCache.addEventListener('noupdate', handleCacheEvent, false);

// Fired if the manifest file returns a 404 or 410.
// This results in the application cache being deleted.
appCache.addEventListener('obsolete', handleCacheEvent, false);

// Fired for each resource listed in the manifest as it is being fetched.
appCache.addEventListener('progress', handleCacheEvent, false);

// Fired when the manifest resources have been newly redownloaded.
appCache.addEventListener('updateready', handleCacheEvent, false);

Se il download del file manifest o di una risorsa specificata non riesce, l'intero aggiornamento non riesce. In caso di errore di questo tipo, il browser continuerà a utilizzare la vecchia cache dell'applicazione.

Riferimenti