Trabalhadores de serviço

Neste artigo, gostaria de falar sobre Service Workers (SW). Os SWs nos permitem deixar nosso aplicativo pronto para funcionar offline para que ele funcione mesmo se não tivermos uma conexão com a internet. Eles também nos permitem usar muitos outros recursos avançados, como notificações push ou sincronização em segundo plano. O SW continua a ser executado mesmo depois que o navegador é fechado, o que significa que os Service Workers continuam em execução. Este é um processo em segundo plano. Portanto, vamos registrar nosso primeiro Service Worker.





(Neste artigo, implementarei a funcionalidade relacionada a SW em JS simples, já que o código é escrito em JS simples, podemos integrar em qualquer estrutura JS como Angular, React ou Vue)





Como primeira etapa, adicione o arquivo sw.js à raiz do projeto. No app.js, precisamos verificar se o SW está disponível no navegador, ou seja, se o SW é compatível com este navegador. Agora que sabemos que os SWs estão disponíveis, podemos executar o método navigator.serviceWorker.register (), especificando o caminho para o arquivo onde nosso SW reside para registrá-lo. Na verdade, esse método retorna uma promessa. Então, para obter informações, uma vez feito isso, podemos nos juntar a ele.





if ('serviceWorker' in navigator) {
  navigator.serviceWorker
    .register('/sw.js')
    .then(event => {
      console.log('Service worker registered', event);
    });
}
      
      



SW, . , SW . , . SW, , , self, « SW», addEventListener (). SW , , , , Service Worker’a. , , . , Service Worker .





self.addEventListener('install', event => {
  console.log('Installing [Service Worker]', event);
});
      
      



. Service Worker’a - , , . caches, API , open (), . , . event.waitUntil (). , . . then . cache.addAll () , .





self.addEventListener('install', event => {
  console.log('Installing [Service Worker]', event);

  event.waitUntil(
    caches.open('static')
      .then(cache => {
        console.log('[Service Worker] Precaching App Shell');
        cache.addAll([
          '/',
          '/index.html',
          '/favicon.ico',
          '/src/js/app.js',
          '/src/js/chart.js',
          '/src/js/materialize.js',
          '/src/js/materialize.min.js',
          '/src/css/materialize.css',
          '/src/css/materialize.min.css',
          '/src/css/style.css',
          'https://fonts.googleapis.com/icon?family=Material+Icons',
          'https://code.jquery.com/jquery-2.1.1.min.js',
          'https://cdn.jsdelivr.net/npm/chart.js@2.8.0'
        ]);
      }));
});
      
      



, -.









, . , . , , - . Fetch , - - , css js xhr. , fetch Service Worker’a , . , , .





self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        if (response) {
          return response;
        } else {
          return fetch(event.request);
        }
      })
    );
});
      
      







event.respondWith () , . Service Worker’ , , fetch. , Service Worker, . , , . cashes.match () , . , . , , , , , , . , , , , fetch (event.request). - . 









, - , « » . , , , . , . , . , , , . , .






    Object.keys(pureData).forEach(key => tmp[sorter[key.toLowerCase()]] = { key, value: pureData[key] });

    tmp.forEach(obj => orderedData[obj.key] = obj.value);

    const ctx = document.getElementById('myChart').getContext('2d');

    new Chart(ctx, {
      type: 'line',
      data: {
          labels: Object.entries(orderedData).map(([key, _]) => key),
          datasets: [{
              label: 'Users',
              backgroundColor: '#26a69a',
              borderColor: '#26a69a',
              fill: false,
              data: Object.entries(orderedData).map(([_, value]) => value),
          }]
      }
    });
  });
};
      
      







, , , .





self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        if (response) {
          return response;
        } else {
          return fetch(event.request)
            .then(res => {
              return caches.open('dynamic')
                .then(cache => {
                  cache.put(event.request.url, res.clone());
                  return res;
                })
            });
        }
      })
    );
});
      
      







, , , . , caches, API open (), . cache.put () , . , , - URL- , . - . , , , , . . . . xhr. , css .









. - , . ? SW . , - , , , , indexedDB. , , SW . SW, . , , . , , Service Worker’y . , . - , , API, . Service Worker’y, ready, , . , . , ( ), . , , . , « ». Service Worker’, , , , , .





if ('serviceWorker' in navigator && 'SyncManager' in window) {
      navigator.serviceWorker.ready
        .then(sw => {
          sw.sync.register('sync-request')
        });
    }
      
      







, «POST DATA» , , indexedDB . , indexedDB. , . . - . «sunday», 10 ( :)). writeData utility.js, . - , , - . .





const syncButton = document.getElementById('sync-button');

syncButton.addEventListener('click', _ => {
    if ('serviceWorker' in navigator && 'SyncManager' in window) {
      navigator.serviceWorker.ready
        .then(sw => {
          const data = {
            id: new Date().getTime(),
            sunday: 10
          };

          writeData('sync-requests', data)
            .then(_ => {
              sw.sync.register('sync-request')
            });
        });
    }
});
      
      







, , - . , , .





self.addEventListener('sync', event => {
  console.log('[Service Worker] Syncing');

  if (event.tag === 'sync-request') {
    event.waitUntil(
      readAllData('sync-requests')
        .then(async data => {
          const requests = [];

          for (const d of data) {
            requests.push(fetch('https://simple-pwa-8a005.firebaseio.com/data.json', {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json'
              },
              body: JSON.stringify({
                sunday: d.sunday
              })
            }));
          }

          const results = await Promise.all(requests);

          results.map((response, index) => {
            if (response.ok) {
              deleteItemFromData('sync-requests', data[index].id);
            }
          })
        })
    );
  }
});
      
      



. event.waitUntil (), , , . , indexedDB ( utility.js), , post , indexedDB, . . . , , «POST DATA» .





Após pressionar o botão "POST DATA", quando estamos offline, nada acontece, mas quando a conexão é restaurada, vemos que a sincronização foi concluída.









E para confirmar que os dados foram realmente enviados para o servidor, primeiro precisamos remover nosso pedido de busca do cache dinâmico e clicar no botão OBTER DADOS. 









É tudo por agora. Até logo. Meu código está disponível no github: https://github.com/Draakan/simplePWA








All Articles