Служащий заставляет JS бежать дважды

Я реализовал сервисный работник из pwabuilder.com, и он работает просто отлично

Проблема в том, что рабочий сервис работает, даже если браузер подключен к сети, поэтому каждая функция js запускается дважды: одна из работника сервиса и одна из моих других файлов js.

Должен ли я посмотреть, является ли он активным работником службы, прежде чем запускать свои функции js, или я должен каким-то образом убедиться, что работник службы не запущен, когда браузер подключен?

Это код, который я запускаю в моем главном индексном файле

if (navigator.serviceWorker.controller) {
            //console.log('[PWA Builder] active service worker found, no need to register')
        } else {
            //Register the ServiceWorker
            navigator.serviceWorker.register('pwabuilder-sw.js', {
                scope: './'
            }).then(function (reg) {
                //console.log('Service worker has been registered for scope:' + reg.scope);
            });
        }

Pwabuilder-sw.js выглядит так:

self.addEventListener('install', function (event) {
var indexPage = new Request('');
event.waitUntil(
    fetch(indexPage).then(function (response) {
        return caches.open('pwabuilder-offline').then(function (cache) {
            //console.log('[PWA Builder] Cached index page during Install' + response.url);
            return cache.put(indexPage, response);
        });
    }));
});

//If any fetch fails, it will look for the request in the cache and serve it from there first
self.addEventListener('fetch', function (event) {
var updateCache = function (request) {
    return caches.open('pwabuilder-offline').then(function (cache) {
        return fetch(request).then(function (response) {
            //console.log('[PWA Builder] add page to offline' + response.url);
            return cache.put(request, response);
        });
    });
};

event.waitUntil(updateCache(event.request));

event.respondWith(
    fetch(event.request).catch(function (error) {
        //Check to see if you have it in the cache
        //Return response
        //If not in the cache, then return error page
        return caches.open('pwabuilder-offline').then(function (cache) {
            return cache.match(event.request).then(function (matching) {
                var report = !matching || matching.status === 404 ? Promise.reject('no-match') : matching;
                return report;
            });
        });
    })
);
});

0 ответов

Сервисные работники должны работать постоянно после регистрации, установки и активации

Работники сервисов управляются событиями, и их основное назначение - выступать в роли агента кэширования, обрабатывать сетевые запросы и хранить контент для автономного использования. Во-вторых, для обработки push-сообщений.

Полагаю, вы понимаете, что для того, чтобы выступать в качестве агента кэширования, сервисный работник будет работать независимо от того, включено приложение или нет. У вас есть различные сценарии кэширования для рассмотрения.

Трудно дать точное решение для упомянутого: "каждая функция js запускается дважды".
Я сомневаюсь, что все функции JS всегда будут выполняться дважды. Кажется, это зависит от реализации.

Сервисные работники не могут иметь область действия выше своего собственного пути, по умолчанию она будет контролировать все ресурсы, находящиеся ниже области действия сервисного работника, эта область также может быть ограничена.

navigation.serviceWorker.register(
    '/pwabuilder-sw.js', { //SW located at the root level here
        scope: '/app/' //to control all resource accessed form within path /app/
    }
);

Я считаю, что скрипт от pwabuilder.com пытается кэшировать все ресурсы, даже ресурсы, которые не должны кэшироваться, такие как запросы POST. Возможно, вам придется изменить политику кэширования в зависимости от того, какой тип ресурсов вы используете.

Здесь нет простого решения и простого ответа не может быть.

В общем случае вы можете использовать работника сервиса для кэширования ресурсов одним из следующих способов:

  • Кэш возвращается к сети

    self.addEventListener('fetch', (event) => {
        event.responseWith(
            caches.match(event.request)
            .then((response) => {
                return response || fetch(event.request);
            })
        );
    });
    
  • Сеть возвращается к кешу

    //Good for resources that update frequently
    //Bad for Intermittend and slow connections
    self.addEventListener('fetch', (event) => {
        event.responseWith(
            fetch(event.request).catch(() => {
                return caches.match(event.request);
            })
        );
    });
    
  • Кеш тогда сетевой

    //Cache then network(1) (send request to cache and network simultaneousely)
    //show cached version first, then update the page when the network data arrives
    var networkDataReceived = false;
    var networkUpdate = fetch('/data.json')
    .then((response) => {
        return response.json();
    }).then((data) => {
        networkDataReceived = true;
        updatePage(data);
    });
    //Cache then network(2)
    caches.match('/data.json')
    .then ((response) => {
        return response.json();
    }).then((data) => {
        if (!networkDataReceived) {
            updatePage(data);
        }
    }).catch(() => {
        return networkUpdate;
    });
    
  • Общий запасной вариант

    self.addEventListener('fetch', (event) => {
        event.responseWith(
            caches.match(event.request)
            .then((response) => {
                return response || fetch(event.request);
            }).catch(() => {
                return caches.match('offline.html');
            })
        )
    });
    

Я надеюсь, что вышеупомянутое поможет хотя бы немного найти точную проблему, с которой вы столкнулись.
Ура и счастливой кодировки!

React добавил этот HOC React.strictMode, который дважды запускает определенные части приложения, такие как конструктор компонентов класса, методы рендеринга и shouldComponentUpdate.
Проверьте документы:
https://reactjs.org/docs/strict-mode.html.

Посмотри, есть ли у тебя <React.StrictMode> в верхней части вашего index.js файл, и если да, вы можете запустить тест без него.

Другие вопросы по тегам