15

Właśnie próbowałem wdrożyć pracowników serwisowych do buforowania niektórych plików JSON i innych zasobów w witrynie statycznej (działającej pod kontrolą wersji localhost w wersji 47.0.2526.73 (wersja 64-bitowa)). Korzystając z cache.addAll(), dodałem moje pliki do pamięci podręcznej, a gdy otworzę kartę zasobów w chrome i kliknę pamięć podręczną, wszystkie pliki zostaną wyświetlone.Pracownik usługi buforuje pliki, ale zdarzenie fetch nigdy nie jest uruchamiane.

screenshot json files shown in cache

Problem mam jest to, że mój pracownik usługa jest wymieniony jako „aktywna” i „działa” w chrome: // service pracownika-wewnętrzne Jednak nie można ustalić, czy pracownik jest faktycznie przechwytywania żądania i udostępnianie buforowanych plików. Dodałem detektor zdarzeń i nawet kiedy pocieszyć rejestrować zdarzenia w służbie pracownicy Dev instancji narzędzia, nigdy nie uderza punkt krytyczny:

this.addEventListener('install', function(event) { 
    event.waitUntil(
    caches.open('v1').then(function(cache) { 
     console.log(cache); 
     return cache.addAll([ 
     '/json/0.json', 
     '/json/1.json', 
     '/json/3.json', 
     '/json/4.json', 
     '/json/5.json', 
     ]); 
    }) 
); 
}); 

this.addEventListener('fetch', function(event) { 
    console.log(event); 
    var response; 
    event.respondWith(caches.match(event.request).catch(function() { 
    return fetch(event.request); 
    }).then(function(r) { 
    response = r; 
    caches.open('v1').then(function(cache) { 
     cache.put(event.request, response); 
    }); 
    return response.clone(); 
    }).catch(function() { 
    })); 
}); 

Zasadniczo używam przez rzeczy dokładnie tak, jak opisano w HTML5 skały pracowników usług intro, ale jestem pewien, że moje zasoby nie są obsługiwane z pamięci podręcznej. Zauważyłem, że zasoby udostępnione przez pracownika serwisu są oznaczone jako takie na karcie sieci devtools w kolumnie rozmiaru przez wskazanie "od pracowników serwisu".

Wygląda na to, że mój kod nie różni się od przykładów, ale z jakiegoś powodu nigdy nie trafia do zdarzenia pobierania. Istotą mojego kodu: https://gist.github.com/srhise/c2099b347f68b958884d

+1

Znalazłeś rozwiązanie? –

+0

Myślę, że wskazówka @Stephen Archers powinna być oznaczona jako poprawna. – user1532132

+0

Tak, należy zaznaczyć odpowiedź @Stephen Archers jako poprawną. –

Odpowiedz

1

Dokładny kod w artykule HTML5Rocks jest

self.addEventListener('fetch', function(event) { 
    event.respondWith(
    caches.match(event.request) 
     .then(function(response) { 
     // Cache hit - return response 
     if (response) { 
      return response; 
     } 

     // IMPORTANT: Clone the request. A request is a stream and 
     // can only be consumed once. Since we are consuming this 
     // once by cache and once by the browser for fetch, we need 
     // to clone the response 
     var fetchRequest = event.request.clone(); 

     return fetch(fetchRequest).then(
      function(response) { 
      // Check if we received a valid response 
      if(!response || response.status !== 200 || response.type !== 'basic') { 
       return response; 
      } 

      // IMPORTANT: Clone the response. A response is a stream 
      // and because we want the browser to consume the response 
      // as well as the cache consuming the response, we need 
      // to clone it so we have 2 stream. 
      var responseToCache = response.clone(); 

      caches.open(CACHE_NAME) 
       .then(function(cache) { 
       cache.put(event.request, responseToCache); 
       }); 

      return response; 
      } 
     ); 
     }) 
    ); 
}); 

Największą rzeczą, którą widzę, jest to, że nie są klonowanie request od pobrania, trzeba sklonować go, ponieważ jest czytany dwa razy, jeden raz, gdy jest używany do uzyskania dostępu do sieci (w fetch) i raz, gdy jest używany jako klucz do pamięci podręcznej.

1

Jeżeli nie widzisz znaku from service worker wtedy strona nie jest kontrolowana przez pracownika serwisu jeszcze (można sprawdzić poprzez kontrolę navigator.serviceWorker.controller na stronie klienta). Domyślnym zachowaniem strony jest jej kontrolowanie przy następnej wizycie po aktywacji SW, więc masz dwie opcje:

  • Odśwież stronę po rejestracji.
  • Użyj odpowiednio metod podczas instalacji i aktywacji, aby zmusić pracownika serwisu do przejęcia kontroli nad klientami tak szybko jak to możliwe.

Spójrz na Service Worker Cookbook, zawiera on JSON cache recipe.

Po rozwiązaniu problemu za pomocą formantu należy naprawić program obsługi. Myślę, że chcesz zastosować zasadę cache-first. Jeśli nie w pamięci podręcznej, przejdź do sieci i wypełnij pamięć podręczną. Aby to zrobić:

self.onfetch = function (event) { 
    var req = event.request; 
    return event.respondWith(function cacheFirst() { 
    // Open your cache. 
    return self.caches.open('v1').then(function (cache) { 
     // Check if the request is in there. 
     return cache.match(req).then(function (res) { 
     // If not match, there is no rejection but an undefined response. 
     if (!res) { 
      // Go to network. 
      return fetch(req.clone()).then(function (res) { 
      // Put in cache and return the network response. 
      return cache.put(req, res.clone()).then(function() { 
       return res; 
      }); 
      }); 
     } 
     return res; 
     }); 
    }); 
    }); 
} 
+0

Nigdy nie widziałem takiej implementacji za pomocą 'return self.caches.open ('v1'). Then (function (cache) {możesz podać mi link do tej oceny –

30

Po przeanalizowaniu twojego problemu i twojego pytania, myślę, że twoja sprawa dotyczy scopingu.

Z tego, co ustaliłem z pracownikami serwisu (przynajmniej z plikami statycznymi), pracownik serwisu ma tylko maksymalny zasięg katalogu, w którym się znajduje. Oznacza to, że nie może załadować plików/żądań/odpowiedzi, które są pobierane z lokalizacji na poziomie lub powyżej jej struktury, tylko poniżej.

Na przykład /js/service-worker.js będzie mógł ładować tylko pliki w/js/{dirName} /.

Dlatego jeśli zmienisz lokalizację swojego pracownika serwisu na katalog główny projektu internetowego, zdarzenie pobierania powinno zostać uruchomione, a zasoby powinny zostać załadowane z pamięci podręcznej.

Coś w rodzaju /service-worker.js, które powinno mieć dostęp do katalogu/json, ponieważ jest głębsze niż plik service-worker.js.

Zostało to wyjaśnione dalej w sekcji "Rejestracja pracownika serwisu". https://developers.google.com/web/fundamentals/getting-started/primers/service-workers

+0

Odpowiedź Stephena powinna być oznaczona jako poprawna. ten sam problem, co mój plik web-worker.js zapisany w podfolderze/assets/js /. Gdy pliki były przechowywane, a pracownik WWW zarejestrowany, nie mógł pobrać żądań pobierania. Po przeniesieniu go do katalogu głównego domena działała poprawnie – user1532132

+0

Czy pracownik serwisu może uzyskać dostęp do plików w swoim własnym katalogu, np. 'app/service-worker.js', czy może odczytać' app/offline-page.html'? – Prefix

+0

@ Prefiks Tak, to powinienem móc. –

1

Długo się z tym zmagałem i wydaje mi się, że brakuje dokumentacji związanej z tą sprawą. Z mojego doświadczenia wynika, że ​​istnieje bardzo ważne rozróżnienie:

Pracownik obsługi może przechwytywać tylko zdarzenia związane z pobieraniem, jeśli znajduje się w zakresie adresu URL lub wykracza poza jego zakres pod numerem.

Na przykład mój plik sw.js znajdował się pod adresem /static/sw.js. Podczas uzyskiwania dostępu do katalogu głównego mojej witryny pod numerem / i próby przechwycenia zdarzeń pobierania do plików js w numerze /static/js/common.js, zdarzenia pobierania nie zostały przechwycone, mimo że zasięg mojego pracownika serwisowego to /static/, a plik js był w /static/js/.

Po przeniesieniu pliku sw.js do zakresu najwyższego poziomu /sw.js wszystkie zdarzenia pobierania zostały przechwycone. Wynika to z tego, że zakres strony, do której uzyskiwałem dostęp za pomocą przeglądarki /, był taki sam jak zakres mojego pliku sw.js /.

Proszę dać mi znać, jeśli to wyjaśnia dla ludzi, lub jeśli jestem niepoprawny!

+0

To było lepsze wytłumaczenie niż inne. Dzięki! –