Najprościej mówiąc aplikacje offline, to takie, które będą działały po utracie połączenia internetowego. Aby było to możliwe, cały dokument html wraz ze wszystkimi zależnościami musi być przechowywany na komputerze użytkownika i dodatkowo potrzebujemy mechanizmów powiadających o utracie (lub odzyskaniu) połączenia. Oczywiście nie jesteśmy w stanie przesłać wszystkiego, ale pewna ilość plików wystarczy, aby zachować funkcjonalność w trybie offline.
Do tej pory przeglądarki udostępniały tzw. Browser Cache. Jego zasada działania jest następująca : przy odwiedzeniu pewnej strony po raz pierwszy, tworzony jest dla niej folder z cache, z pobranymi plikami (html, js, css, img). Przy kolejnych requestach o ten plik pobierany jest on z cache (jeżeli w międzyczasie nie został zmieniony), przez co czas od wysłania żądania do wyświetlenia całej zawartości strony jest znacznie krótszy. Gdy utracone zostaje połączenie, z cache pobrany zostanie tylko dokument html, bez plików js, css i plików graficznych.
Nowa funkcjonalność to Application Cache, który również jest miejscem na komputerze użytkownika, z którego strony mogą być dostarczane. Różnica polega na tym, że pliki nie są pobierane pojedynczo, a "tranzakcyjnie". Oznacza to mniej więcej tyle, że nie będziemy mogli otworzyć strony, jeżeli którykolwiek z plików nie został pobrany. Z drugiej strony, jeżeli transakcja zostanie zakończona pomyślnie, to mamy pewność, że cała zawartość strony znajduje się na naszym dysku.
Skąd przeglądarka ma wiedzieć o tym, które pliki tworzą razem aplikację ? Mówi o tym plik manifestu, o którego strukturze nieco więcej zostanie napisane poniżej. Warto pamiętać, że zmiana dowolnego pliku aplikacji na serwerze nie spowoduje jego aktualizacji po stronie klienta. Dzieje się tak dlatego, że pliki aktualizowane są dopiero przy zmianie manifestu.
Aby móc skorzystać z funkcjonalności aplikacji offline, nie wolno korzystać z browser cache, a także należy pliki manifestu przesyłać ze specjalnym Content-Type w nagłówku. Przykładowa konfiguracja serwera w Node.js poniżej.
var express = require('express');
var http = require('http');
var app = express();
app.use(express.static(__dirname));
app.get("/cache.manifest", function(req, res){
res.header("Content-Type", "text/cache-manifest");
res.end("CACHE MANIFEST");
});
app.listen('1027');
Manifest
Dołącza się go w znaczniku html, może być plikiem o dowolnym rozszerzeniu, np:
<html manifest="cache.manifest">
Przykładowy plik manifestu:
CACHE MANIFEST
# version 1.2
CACHE:
script.js
HTML5_Logo.png
http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.2/jquery.min.js
NETWORK:
jquery.jpg
Mamy dostępne kilka sekcji. Wersja może być przydatna, ponieważ zmiana wersji spowoduje pobranie na nowo plików przez przeglądarkę.
CACHE - lista plików do pobrania
NETWORK - pliki, które z jakiegoś powodu muszą być pobierane zawsze
FALLBACK - zamienniki dla plików, których nie da się pobrać gdy aplikacja przejdzie w tryb offline.
W javascripcie poprzez obiekt applicationCache, możemy obsłużyć zdarzenia, jakie występują w przypadku update'u manifestu oraz pobierania plików z Application Cache.
Pełny kod z przykładem obsługi wszystkich dostępnych zdarzeń poniżej:
<!doctype html>
<html manifest="cache.manifest">
<head>
<meta charset="utf-8">
<title>Offline Web Applications</title>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript">
$(function(){
window.applicationCache.onupdateready = function(e){
console.log('onupdateready');
applicationCache.swapCache();
}
});
</script>
</head>
<body>
<h1>hello world</h1>
</body>
</html>
$(function(){
if(window.applicationCache){
console.log('supporting app cache');
window.applicationCache.onchecking = function(e){
console.log('onchecking');
}
window.applicationCache.oncached = function(e){
console.log('oncached');
}
window.applicationCache.onupdate = function(e){
console.log('onupdate');
}
window.applicationCache.onobsolete = function(e){
console.log('onobsolete');
}
window.applicationCache.ondownloading = function(e){
console.log('ondownloading');
}
}
});