OFFLINE WEB COM 
SERVICE WORKERS
sergiolopes.org 
@sergio_caelum
WEB. OFFLINE?
os primórdios do HTML5 offline 
Application Cache API
Minha página offline… 
<html manifest="demo.appcache">
O manifesto… 
CACHE MANIFEST 
/index.html 
/imagens/logo.png 
/javascript/script.js 
/css/estilo.css
O manifesto… 
CACHE MANIFEST 
/index.html 
/imagens/logo.png 
/javascript/script.js 
/css/estilo.css 
NETWORK: 
http://www.google-analytics.com/ga.js
O manifesto… 
CACHE MANIFEST 
/index.html 
/imagens/logo.png 
/javascript/script.js 
/css/estilo.css 
NETWORK: 
http://www.google-analytics.com/ga.js 
FALLBACK: 
/img/avatares/ /img/avatar-generico.png
Pronto! 
O maravilhoso AppCache entra em ação.
Tem que acertar o mime-type no servidor.
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL.
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL. 
Sempre cacheia a página.
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL. 
Sempre cacheia a página. 
Nada pode dar erro 404 ou 500.
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL. 
Sempre cacheia a página. 
Nada pode dar erro 404 ou 500. 
Cuidado pra não cachear o manifesto.
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL. 
Sempre cacheia a página. 
Nada pode dar erro 404 ou 500. 
Cuidado pra não cachear o manifesto. 
Usuário não pode controlar nada.
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL. 
Sempre cacheia a página. 
Nada pode dar erro 404 ou 500. 
Cuidado pra não cachear o manifesto. 
Usuário não pode controlar nada. 
Impossível escolher o que cachear.
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL. 
Sempre cacheia a página. 
Nada pode dar erro 404 ou 500. 
Cuidado pra não cachear o manifesto. 
Usuário não pode controlar nada. 
Impossível escolher o que cachear. 
Potencial para detonar o 3G do usuário.
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL. 
Sempre cacheia a página. 
Nada pode dar erro 404 ou 500. 
Cuidado pra não cachear o manifesto. 
Usuário não pode controlar nada. 
Impossível escolher o que cachear. 
Potencial para detonar o 3G do usuário. 
Remover o cache é um parto.
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL. 
Sempre cacheia a página. 
Nada pode dar erro 404 ou 500. 
Cuidado pra não cachear o manifesto. 
Usuário não pode controlar nada. 
Impossível escolher o que cachear. 
Potencial para detonar o 3G do usuário. 
Remover o cache é um parto. 
Não posso impedir update automático.
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL. 
Sempre cacheia a página. 
Nada pode dar erro 404 ou 500. 
Cuidado pra não cachear o manifesto. 
Usuário não pode controlar nada. 
Impossível escolher o que cachear. 
Potencial para detonar o 3G do usuário. 
Remover o cache é um parto. 
Não posso impedir update automático. 
Terrível pra desenvolver e debugar.
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL. 
Sempre cacheia a página. 
Nada pode dar erro 404 ou 500. 
Cuidado pra não cachear o manifesto. 
Usuário não pode controlar nada. 
Impossível escolher o que cachear. 
Potencial para detonar o 3G do usuário. 
Remover o cache é um parto. 
Não posso impedir update automático. 
Terrível pra desenvolver e debugar. …
Tem que acertar o mime-type no servidor. 
Não posso esquecer nenhuma URL. 
Sempre cacheia AppCache a página. 
é 
Nada pode dar erro limitado 404 ou 500. 
e 
Cuidado pra não cachear o manifesto. 
Usuário não pode controlar nada. 
Impossível chato, escolher complicado. 
o que cachear. 
Potencial para detonar o 3G do usuário. 
Remover o cache é um parto. 
Não posso impedir update automático. 
Terrível pra desenvolver e debugar. …
http://sergiolopes.org/palestra-appcache-html5-offline/
Declarativo e Mágico.
SERVICE 
WORKERS
<!DOCTYPE html> 
<html> 
<head> 
</head> 
<body> 
<h1>Página offline</h1> 
</body> 
</html>
<!DOCTYPE html> 
<html> 
<head> 
<script> 
navigator.serviceWorker.register('o-futuro.js'); 
</script> 
</head> 
<body> 
<h1>Página offline</h1> 
</body> 
</html>
this.onfetch = function(event) { 
console.log(event.request.url); 
};
this.onfetch = function(event) { 
event.respondWith( 
new Response("<h1>Página offline!</h1>") 
); 
};
SERVICE 
WORKER 
É um Worker orientado a eventos, que controla as 
páginas em background. Lá, tudo é assíncrono, e 
ele pode interceptar chamadas de rede e usar um 
cache de recursos.
JAVASCRIPT COMUM 
<script src="script.js" async></script>
JAVASCRIPT COMUM 
<script src="script.js" async></script> 
DOM 
CSSOM 
LAYOUT 
EVENTOS 
SCROLL
JAVASCRIPT COMUM 
<script src="script.js" async></script> 
DOM 
script 
CSSOM 
script 
LAYOUT 
script 
EVENTOS 
script 
SCROLL
WEB WORKERS 
<script> new Worker('worker.js'); </script>
WEB WORKERS 
<script> new Worker('worker.js'); </script> 
DOM 
CSSOM 
LAYOUT 
EVENTOS 
SCROLL
WEB WORKERS 
<script> new Worker('worker.js'); </script> 
script 
script 
script 
script 
DOM 
CSSOM 
LAYOUT 
EVENTOS 
SCROLL
WEB WORKERS 
PÁGINA 
#1
PÁGINA 
#1 
web worker A 
WEB WORKERS
PÁGINA 
#1 
web worker A 
WEB WORKERS 
web worker B
PÁGINA 
#1 
web worker A 
WEB WORKERS 
web worker B 
PÁGINA 
#2 
web worker A 
web worker B
WEB WORKERS 
PÁGINA 
#2 
web worker A 
web worker B
WEB WORKERS
<script>navigator.serviceWorker.register('sw.js');</PÁGINA 
#1 
Service Worker 
PÁGINA 
#2 
PÁGINA 
#3 
SERVICE WORKER
SERVICE WORKER 
<script>navigator.serviceWorker.register('sw.js');</PÁGINA 
#1 
Service Worker 
PÁGINA 
#2
SERVICE WORKER 
<script>navigator.serviceWorker.register('sw.js');</PÁGINA 
#1 
Service Worker
SERVICE WORKER 
<script>navigator.serviceWorker.register('sw.js');</Service Worker
SERVICE 
WORKER 
É um Worker orientado a eventos, que controla as 
páginas em background. Lá, tudo é assíncrono, e 
ele pode interceptar chamadas de rede e usar um 
cache de recursos.
PROMISES 
navigator.serviceWorker.register('sw.js').then(function(){ 
console.log('Registrado!'); 
}, function(erro) { 
console.log('Problemas', erro); 
});
EVENTOS 
this.oninstall = function(event) { 
console.log('instalou'); 
}; 
this.onactivate = function(event) { 
console.log('ativou'); 
}; 
this.onfetch = function(event) { 
event.respondWith( 
new Response("<h1>Página offline!</h1>”) 
); 
};
CACHE API
caches.open('aplicacao');
caches.open('aplicacao').then(function(cache) { 
});
caches.open('aplicacao').then(function(cache) { 
cache.add('pg.html'); 
});
caches.open('aplicacao').then(function(cache) { 
cache.put('pg.html', new Response("Página offline")); 
});
caches.open('aplicacao').then(function(cache) { 
cache.add('pg.html'); 
cache.add('style.css'); 
});
caches.open('aplicacao').then(function(cache) { 
cache.addAll([ 
'/index.html', 
'/style.css', 
'/logo.png', 
'/contato.html', 
'http://code.jquery.com/jquery-2.1.1.min.js' 
]); 
})
caches.open('aplicacao').then(function(cache) { 
return cache.addAll([ 
'/index.html', 
'/style.css', 
'/logo.png', 
'/contato.html', 
'http://code.jquery.com/jquery-2.1.1.min.js' 
]); 
})
this.oninstall = function(event) { 
caches.open('aplicacao').then(function(cache) { 
return cache.addAll([ 
'/index.html', 
'/style.css', 
'/logo.png', 
'/contato.html', 
'http://code.jquery.com/jquery-2.1.1.min.js' 
]); 
}) 
};
this.oninstall = function(event) { 
event.waitUntil( 
caches.open('aplicacao').then(function(cache) { 
return cache.addAll([ 
'/index.html', 
'/style.css', 
'/logo.png', 
'/contato.html', 
'http://code.jquery.com/jquery-2.1.1.min.js' 
]); 
}) 
); 
};
CACHE 
programático & controlável
CACHE 
programático & controlável 
Cacheio URLs como quero.
CACHE 
programático & controlável 
Cacheio URLs como quero. 
Gero endereços num for com certa regra.
CACHE 
programático & controlável 
Cacheio URLs como quero. 
Gero endereços num for com certa regra. 
Recursos diferentes dependendo do browser.
CACHE 
programático & controlável 
Cacheio URLs como quero. 
Gero endereços num for com certa regra. 
Recursos diferentes dependendo do browser. 
Levo em conta alguma preferência do usuário.
CACHE 
programático & controlável 
Cacheio URLs como quero. 
Gero endereços num for com certa regra. 
Recursos diferentes dependendo do browser. 
Levo em conta alguma preferência do usuário. 
Mudo de acordo com hardware e contexto.
RESPOSTA OFFLINE
this.onfetch = function(event) { 
console.log(event.request.url); 
};
this.onfetch = function(event) { 
event.respondWith( 
new Response(‘conteúdo!') 
); 
};
this.onfetch = function(event) { 
event.respondWith( 
caches.match(event.request) 
); 
};
RESPOSTA DO CACHE
RESPOSTA DO CACHE 
E se não existir?
this.onfetch = function(event) { 
event.respondWith( 
caches.match(event.request).then(function(response){ 
}) 
); 
};
this.onfetch = function(event) { 
event.respondWith( 
caches.match(event.request).then(function(response){ 
return response || event.default(); 
}) 
); 
};
BAIXA NA REDE
BAIXA NA REDE 
E se estiver offline?
this.onfetch = function(event) { 
event.respondWith( 
caches.match(event.request).then(function(response){ 
return response || event.default(); 
}).catch(function() { 
return caches.match('/contato.html'); 
}) 
); 
};
FALLBACK DE URLs
RESPOSTA 
programática & controlável
RESPOSTA 
programática & controlável 
Busco no cache.
RESPOSTA 
programática & controlável 
Busco no cache. 
Busco na rede.
RESPOSTA 
programática & controlável 
Busco no cache. 
Busco na rede. 
Devolvo fallback.
RESPOSTA 
programática & controlável 
Busco no cache. 
Busco na rede. 
Devolvo fallback. 
Construo resposta na mão.
RESPOSTA 
programática & controlável 
Busco no cache. 
Busco na rede. 
Devolvo fallback. 
Construo resposta na mão. 
Tudo com a lógica e a sequência que eu quiser.
ATUALIZAÇÕES
Mudo o worker.js
Mudo o worker.js 
Detecta na próxima navegação.
Mudo o worker.js 
Detecta na próxima navegação. 
Dispara instalação (oninstall) em background.
Mudo o worker.js 
Detecta na próxima navegação. 
Dispara instalação (oninstall) em background. 
(worker original ainda comanda a página)
Mudo o worker.js 
Detecta na próxima navegação. 
Dispara instalação (oninstall) em background. 
(worker original ainda comanda a página) 
Fecho a página.
Mudo o worker.js 
Detecta na próxima navegação. 
Dispara instalação (oninstall) em background. 
(worker original ainda comanda a página) 
Fecho a página. 
Worker velho é desativado.
Mudo o worker.js 
Detecta na próxima navegação. 
Dispara instalação (oninstall) em background. 
(worker original ainda comanda a página) 
Fecho a página. 
Worker velho é desativado. 
Novo worker é ativado (onactivate).
Mudo o worker.js 
Detecta na próxima navegação. 
Dispara instalação (oninstall) em background. 
(worker original ainda comanda a página) 
Fecho a página. 
Worker velho é desativado. 
Novo worker é ativado (onactivate). 
(novo worker em ação)
Mudo o worker.js 
Detecta na próxima navegação. 
Dispara instalação (oninstall) em background. 
(worker original ainda comanda a página) 
Fecho a página. 
Worker velho é desativado. 
Novo worker é ativado (onactivate). 
(novo worker em ação) 
Abro a página de novo.
this.oninstall = function(event) { 
event.waitUntil( 
caches.open('aplicacao-v2').then(function(cache) return cache.addAll([ 
'/index.html', 
'/style.css', 
'/logo.png', 
'/contato.html', 
'http://code.jquery.com/jquery-2.1.1.min.js' 
]); 
}) 
); 
};
this.onactivate = function(event) { 
event.waitUntil( 
caches.delete('aplicacao-v1') 
); 
};
ATUALIZAÇÃO
ATUALIZAÇÃO 
Totalmente em background.
ATUALIZAÇÃO 
Totalmente em background. 
Não incomoda o usuário.
ATUALIZAÇÃO 
Totalmente em background. 
Não incomoda o usuário. 
Só troca no próximo acesso.
ATUALIZAÇÃO 
Totalmente em background. 
Não incomoda o usuário. 
Só troca no próximo acesso. 
Chrome-like.
detalhes dos 
SERVICE 
WORKERS
controle de escopo
navigator.serviceWorker.register('worker.js');
navigator.serviceWorker.register('worker.js', { 
scope: '/blog/' 
});
HTTPS only
tudo assíncrono
pode ser morto a 
qualquer momento
muito mais poderoso 
muito mais complicado
ainda não existe 
em nenhum browser
FUTURO FANTÁSTICO
BACKGROUND 
SYNC
postaTweet(texto);
try { 
postaTweet(texto); 
} catch (err) { 
}
try { 
postaTweet(texto); 
} catch (err) { 
salvaTweet(texto); 
registration.sync.register('envia-tweet'); 
}
postaTweet(texto).catch(function(){ 
});
postaTweet(texto).catch(function(){ 
salvaTweet(texto).then(function(){ 
}).then(function(){ 
}); 
});
postaTweet(texto).catch(function(){ 
return salvaTweet(texto).then(function(){ 
return navigator.serviceWorker.ready; 
}).then(function(registration){ 
return registration.sync.register('envia-tweet'); 
}); 
});
this.onsync = function (event) { 
if (event.id === 'envia-tweet') { 
} 
};
this.onsync = function (event) { 
if (event.id === 'envia-tweet') { 
event.waitUntil( 
carregaTweet().then(function(texto){ 
postaTweet(texto); 
}) 
); 
} 
};
registration.sync.register('atualiza-inbox', { 
minInterval: 60 * 60 * 1000 
});
PUSH 
NOTIFICATION
registration.pushRegistrationManager.register()
registration.pushRegistrationManager.register() 
.then(function(detalhes) { 
});
registration.pushRegistrationManager.register() 
.then(function(detalhes) { 
return avisaServidor(detalhes); 
});
this.onpush = function(event) { 
if (event.message.data == 'nova-mensagem') { 
} 
};
this.onpush = function(event) { 
if (event.message.data == 'nova-mensagem') { 
event.waitUntil( 
atualizaMensagens().then(function(){ 
}) 
); 
} 
};
this.onpush = function(event) { 
if (event.message.data == 'nova-mensagem') { 
event.waitUntil( 
atualizaMensagens().then(function(){ 
new Notification("Chegou mensagem!"); 
}) 
); 
} 
};
this.onnotificationclick = function(event) { 
};
this.onnotificationclick = function(event) { 
new ServiceWorkerClient('/mensagens.html'); 
};
GEOFENCING
ALARMES 
TEMPORAIS
SERVICE 
WORKERS 
hoje, depois do evento
estude Service Workers 
hoje. esse é o futuro.
brinque no Chrome 
Chrome Canary - chrome://flags 
#enable-experimental-web-platform-features
vote no 
status.modern.ie
use AppCache 
como fallback
offline como 
progressive enhancement 
if ('serviceWorker' in navigator) { 
}
pense offline first
OFFLINE WEB COM 
SERVICE WORKERS
OBRIGADO! 
sergiolopes.org 
@sergio_caelum

Offline Web com Service Workers - Sérgio Lopes