javascriptpush-notificationes6-promiseservice-workerpush-api

push subscription error not triggering catch


I am trying to take a specific action if my push registration fails. To make the subscription fail, I have removed the <link> to the manifest.json file (I'm using Chrome). I get the following error as expected:

Uncaught (in promise) DOMException: Registration failed - manifest empty or missing

However this error comes from index.html:1 rather than main.js, where the subscription code lives:

function subscribe() {
  navigator.serviceWorker.ready
  .then(function(reg) {
    reg.pushManager.getSubscription()
    .then(function(sub) {
      if (!sub) {
        reg.pushManager.subscribe({userVisibleOnly: true})
        .then(function(subscription) {
          console.log('Subscribed to push,', subscription);
        });
      } else {
        console.log('Already subscribed');
      }
    });
  })
  .catch(function(e) {
    console.log('catch!');
    // Do something
  });
}

And (I suspect as a result) the catch block is not triggering. Is this correct behavior or am I likely doing something wrong?

More details: I am trying to simulate offline behavior, which is why I have removed the link to manifest.json (which would be unavailable offline unless cached). If the subscription fails because the app is offline, I'd like to take action in the catch (e.g. queue an analytics hit or update UI).


Solution

  • As @bvakiti said in his comment, a catch block must be on the same "level" as the rejecting promise. Since in this case the reg.pushManager.subscribe({userVisibleOnly: true}) code is whats throwing the error, there needs to be a catch on the end of that promise chain. Updated code:

    navigator.serviceWorker.ready
    .then(function(reg) {
      reg.pushManager.getSubscription()
      .then(function(sub) {
        if (!sub) {
          reg.pushManager.subscribe({userVisibleOnly: true})
          .then(function(subscription) {
            console.log('Subscribed to push,', subscription);
          })
          // Catch here now!
          .catch(function(e) {
            console.log('catch statements must be on the same level!');
          });
        } else {
          console.log('Already subscribed');
        }
      }); // could add catch here too
    }); // no catch needed here, serviceWorker.ready never rejects
    

    Note that for the other async "levels", I would also need to add catches for their corresponding promises, as shown with comments (except for serviceWorker.ready promise, which actually never rejects.