skip to Main Content

I have this code in my Service Worker:

self.addEventListener('fetch', (event) => {
    event.respondWith(new Promise(async (resolve, reject) => {
        const req = event.request;
        try {
            const res = new HTTPResponse(resolve, reject);
            await chain_handlers(this._middlewares, function(fn, next) {
                return fn(req, res, next);
            });
            const method = req.method;
            const url = new URL(req.url);
            const path = normalize_url(url.pathname);
            const routes = this._routes[method];
            if (routes) {
                const match = this._parser.pick(routes, path);
                if (match.length) {
                    const [first_match] = match;
                    const fns = [...this._middlewares, ...routes[first_match.pattern]];
                    req.params = first_match.data;
                    setTimeout(function() {
                        reject('Timeout Error');
                    }, this._timeout);
                    await chain_handlers(fns, (fn, next) => {
                        return fn(req, res, next);
                    });
                    return;
                }
            }
            if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') {
                return;
            }
            //request = credentials: 'include'
            fetch(event.request).then(resolve).catch(reject);
        } catch(error) {
            this._handle_error(resolve, req, error);
        }
    }));
});

And I’ve noticed that when the JS file is blocked by AdBlocker (uBlock) Chrome Extension I’ve got an error with a stack trace in dev tools:

Google Chrome Dev tools with exception and stack trace

The errors came from Analytics (OWA) that I have on my blog.

So the question is what is the purpose of reject in a fetch event? And how to properly handle Errors like this in service Workers to not get a stack trace?

EDIT: I’ve needed to put my whole code of the fetch even because got a lot of comments about async/await and Promise constructor, and it’s not feasible to use one without the other in my case.

This doesn’t changes the question.

EDIT2:

So I’ve minimized the code, this is my real question I don’t care that I have anti-pattern a lot of libraries do things that you don’t normally do I don’t care. I just want to get the answer to this simple question:

How to don’t get a stack trace and how and what is rejection in Promise for fetch event for? How to properly handle fetch rejection in a Service Worker fetch event?

This is simplified code:


self.addEventListener('fetch', (event) => {
  event.respondWith(new Promise((resolve, reject) => {
    fetch(event.request).then(resolve).catch(reject);
  }));
});

self.addEventListener('activate', (event) => {
  event.waitUntil(clients.claim());
});

And this is the console when AdBlock is on:

Console error with stack trace

2

Answers


  1. Chosen as BEST ANSWER

    This is not intuitive but you need to catch and ignore the promise rejection when using the Promise constructor:

    self.addEventListener('fetch', (event) => {
      event.respondWith((new Promise((resolve, reject) => {
        fetch(event.request).then(resolve).catch(reject);
      })).catch(() => {}));
    });
    

    You will still get an error in the console. This is the console output:

    Dev Tools Console with as just the error message

    As you can see from the above screenshot there are no stack traces but the error about blocking the request is still there.


  2. It appears the unhandled rejection is a problem with Chrome’s respondWith implementation. It does handle both fulfillment and rejection of the argument promise, so it should not leave the rejected promise marked as unhandled.

    You can work around this by handling (by ignoring) the rejection of the promise before passing it to respondWith:

    async function handleRequest(request) {
        if (…) {
            … // do async stuff
            const result = await chain_handlers(this._middlewares);
            return result;
        }
        if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') {
             return;
        }
        return fetch(request);
    }
    self.addEventListener('fetch', (event) => {
        const promise = handleRequest(event.request);
        promise.catch(_ => { /* https://bugs.chromium.org/p/chromium/issues/detail?id=1475744 */ }); // suppress unhandled rejection
        event.respondWith(promise);
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search