简体   繁体   中英

How do I handle a rejected Promise in a Service Worker install event?

I have a case where I need to catch a rejected promise from a Service Worker install event and display an error message.

I've set up a test Service Worker called testsw.js which immediately throws a rejected promise, like so:

console.log("Hello from SW");
self.addEventListener('install', function (evt) {
    evt.waitUntil(Promise.reject(new Error("Test")));
})

and I'm registering the Service Worker using the following code:

navigator.serviceWorker.register('/testsw.js')
        .then(function (reg) {
             console.log("Service worker successfully registered.", reg);
        })
        .catch(function (err) {
            console.error("Service worker failed to register.", err);
        })

The catch function is never hit in this case, and registering the Service worker results in this console output:

testsw.js:1 Hello from SW
testsw.js:3 Uncaught (in promise) Error: Test
    at testsw.js:3
(anonymous) @ testsw.js:3
(index):468 Service worker successfully registered. ServiceWorkerRegistration

I've already tried wrapping the rejected promise in a function and calling that in evt.waitUntil() , as well as throwing a plain Error, with no change. The Service Worker is still put into the redundant state, which is good, but I still need to know that the installation failed.

Am I misunderstanding how rejected promises work in a Service Worker installation? Is there something misconfigured in the registration that would make it always hit the then block, even if the promise is rejected? Failing that, is there something in the ServiceWorkerRegistration class or somewhere else that would tell us that the service worker failed to install or update?

If it makes a difference, this was tested in Chrome 77 and Edge 83 with no success.

The registration promise fulfills as soon as the script has been loaded and the worker has been registered, regardless whether it fails installation or not (it might not even need to be installed any more). To check whether the installation failed, you need to listen to statechange events from the installing worker :

navigator.serviceWorker.register('/testsw.js').then(function (reg) {
     console.log("Service worker successfully registered.", reg);
     if (reg.installing) {
         reg.installing.onstatechange = function(e) {
             if (e.target.state == 'installed') {
                 console.log("Service worker successfully installed.");
             } else if (e.target.state == 'redundant') {
                 console.log("Service worker failed to install.");
             }
         };
     }
}).catch(function (err) {
    console.error("Service worker failed to register.", err);
});

If you want to also display the cause of the failed installation, it seems you have to do that yourself by handling the error in the install handler and pass a message to originating page. Maybe also try listening to error events on the installing worker. You might however have to fire these manually, as unhandled promise rejections don't get caught automatically :

console.log("Hello from SW");
self.addEventListener('install', function (evt) {
    const installation = Promise.reject(new Error("Test"));
    evt.waitUntil(installation);
    installation.catch(err => {
        self.clients.matchAll({includeUncontrolled: true}).then(clients => {
            for (const client of clients)
                client.postMessage({type: 'error', message: err.message});
        });
    });
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM