服务人员使js运行两次

时间:2018-10-26 12:10:41

标签: javascript service-worker progressive-web-apps

我从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;
            });
        });
    })
);
});

2 个答案:

答案 0 :(得分:0)

  

服务人员一经注册,安装和激活,就可以一直工作

服务人员是事件驱动的,其主要用途是充当缓存代理处理网络请求存储内容处理推送消息

  

我相信您了解,为了充当缓存代理,无论应用程序是联机还是脱机,服务工作者都将运行。您需要考虑各种缓存方案。

很难为上述问题提供确切的解决方案:“每个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');
            })
        )
    });
    

我希望以上内容至少可以帮助您找到您所面临的确切问题。
干杯和快乐!

答案 1 :(得分:0)

React添加了此React.strictMode HOC,它可以运行应用程序某些特定部分的两倍,例如类组件构造函数,render和shouldComponentUpdate方法。
检查文档:
https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects

查看<React.StrictMode>文件顶部是否有index.js,如果是,则可能需要运行没有它的测试。