Alanthir
Alanthir

Reputation: 9

Why does serviceworker cause every second jquery post to instantly stall out?

What I stated in the title only happens in chrome as in firefox "('serviceWorker' in navigator)" is always false and "console.warn('Service workers aren\'t supported in this browser.');" triggers instead.

If you clear the browser or run incognito then it works initially but when you log out for the first time and then log back in the problems start.

This is what it looks like in the network log

Here's the code in which I register the SW:

function activateSW(){
    if('serviceWorker' in navigator){
        if(window.location.pathname != '/'){
            //register with API
            if(!navigator.serviceWorker.controller) navigator.serviceWorker.register('/service-worker', { scope: '/' });
            //once registration is complete
            navigator.serviceWorker.ready.then(function(serviceWorkerRegistration){
                //get subscription
                serviceWorkerRegistration.pushManager.getSubscription().then(function(subscription){
                    //enable the user to alter the subscription
                    $('.js-enable-sub-test').removeAttr("disabled");
                    //set it to allready subscribed if it is so
                    if(subscription){
                        $('.js-enable-sub-test').prop("checked", true);
                        $('.js-enable-sub-test').parent().addClass('checked');
                    }
                });
            });
        }   
    }else{  
        console.warn('Service workers aren\'t supported in this browser.');  
    } 
}

'/service-worker' is a request that gets sent to index.php (via .htaccess). It eventually end up in this function:

function serviceworkerJS($params){

    $hash = API::request('settings', 'getSWHash', '');

    if($hash != false){
        setcookie('SW_Hash', $hash, time() + (86400 * 365 * 10), "/");

        header('Content-type: text/javascript');

        echo "'use strict';
var hash = '".$hash."';";

        include(ROOT_PATH.'public/js/service-worker.js');
    }elseif(isset($_COOKIE['SW_Hash'])){
        header('Content-type: text/javascript');

        echo "'use strict';
var hash = '".$_COOKIE['SW_Hash']."';";

        include(ROOT_PATH.'public/js/service-worker.js');
    }else{
        header('HTTP/1.1 404 Not Found');
    }

}

Service-worker.js as seen in chrome://serviceworker-internals/ looks like this: (Several references to the adress has been replaced by stars)

'use strict';
var hash = 'bd8e78963deebf350f851fbf8cdc5080';
var *****_API_ENDPOINT = 'https://*********.***/';

//For displaying notifications
function showNotification(title, body, icon, data, id) {
    var notificationOptions = {
        body: body,
        icon: icon,
        tag: id,
        data: data
    };
    //possibly unnecessary
    if(self.registration.showNotification){
        return self.registration.showNotification(title, notificationOptions);
    }else{
        return new Notification(title, notificationOptions);
    }
}

//asks the server for messages and sends them for displaying.
function getMessages(event){
    //showNotification('debug', 'initial', '', '', 'debug1');

    //build question
    var FD = new FormData();
    FD.append('hash', hash);

    //ask start20 for the notifications
    event.waitUntil(
        fetch(*****_API_ENDPOINT + 'ajax-get-SW-notification/', {method: 'post', body: FD}).then(function(response){

            //something went wrong
            if (response.status !== 200){
                console.log('Error communicating with ******, code: ' + response.status);
                showNotification('debug', 'picnic', '', '', 'debug2');
                throw new Error();
            }

            //decode the response
            return response.json().then(function(data){

                var len = data.notifications.length;
//showNotification('debug', len, '', '', 'propertyName');
                //Display
                for(var i = 0; i < len -1; i++){
                    showNotification(data.notifications[i].title, 
                                    data.notifications[i].body, 
                                    data.notifications[i].imageurl, 
                                    data.notifications[i].linkurl,
                                    data.notifications[i].hash);
                }

                //the last one needs to be returned to complete the promise
                return showNotification(data.notifications[len -1].title, 
                                        data.notifications[len -1].body, 
                                        data.notifications[len -1].imageurl, 
                                        data.notifications[len -1].linkurl,
                                        data.notifications[len -1].hash);
            });
        })
    );
}

//when the user installs a new SW
/*self.addEventListener('activate', function(event){
    //getMessages(event);
    //event.preventDefault();
    event.waitUntil(return self.registration.showNotification('bicnic', { body: '*p' }));
});*/

//when the serviceworker gets a puch from the server
self.addEventListener('push', function(event){
    getMessages(event);
    event.preventDefault();
});

//get the link associated witht he message when a user clicks on it
self.addEventListener('notificationclick', function(event){

    //ask if the notification has any link associated with it
    var FD = new FormData();
    FD.append('hash', event.notification.tag);

    //get the link
    event.waitUntil(
        fetch(******_API_ENDPOINT + 'ajax-notification-has-link/', {method: 'post', body: FD}).then(function(response){

            //something went wrong
            if (response.status !== 200){
                console.log('Error communicating with ********, code: ' + response.status);
                return;
            }

            //decode the response
            return response.json().then(function(data){

                //if there's a link associated with the message hash
                if(data.link){
                    console.log(******_API_ENDPOINT + 'notification-link/' + event.notification.tag);
                    return clients.openWindow(*****_API_ENDPOINT + 'notification-link/' + event.notification.tag);
                }

            });
        })
    );

});


//unnecessary?
/*self.addEventListener('install', function(event){
    //event.preventDefault();
});

self.addEventListener("fetch", function(event) {

});//*/

Now if you comment away "if(!navigator.serviceWorker.controller) navigator.serviceWorker.register( '/service-worker', { scope: '/' });" then the issue disappears but ofc the serviceworker subscribing and unsubscribing stops working. (The if statement doesn't seem to do much and was only added in an attempt to solve this)

I've tried numerous versions of activateSW() with various conditions for the different expressions to run and haven't managed to make a version that works without breaking the serviceworker. I have also tried to catch errors on various points (registration, posts) but this has been unsuccessful as none of them throws any.

What I suspect might be the problem is that as you register the serviceworker an activate event is triggered. Now if you catch this and complete the event promise then you become unable to subscribe. However I suspect that the serviceworker remains active as you log out and this causes a problem.

If you have questions or want to see more code then just ask.

edit; here's the solution:

self.addEventListener("fetch", function(event) {
    event.respondWith(
        fetch(event.request)
    );
});

Upvotes: 0

Views: 1361

Answers (1)

Jeff Posnick
Jeff Posnick

Reputation: 56044

What you're seeing is confusing noise in the Network panel of Chrome DevTools, but shouldn't have a practical effect on your application's behavior.

If a service worker controls a page but doesn't include a fetch event handler, current versions of Chrome (M44 stable, and M46 canary) end up logging all network requests in the Network panel with (canceled) status, like you're seeing. The actual request is still made without service worker intervention, which is the second, successful logged entry. Things should work as expected from the perspective of your page, but I completely understand the confusion.

I have heard that there are plans to make Chrome's service worker implementation behave much more like a "no-op" when a network request is made and there's no fetch event handler. I don't know how far along those plans are, but I would expect that the noise you're seeing logged to go away once that happens.

Upvotes: 1

Related Questions