Royi Namir
Royi Namir

Reputation: 148524

How can I catch asynchronous-non-promised errors ? ( react to that specific error)

I know that there are answers out there but I didn't find a specific answer to my actual question.

Currently I use the following pattern a lot :

 class A
 {
     getLocation()
     {
         return Promise.reject(2222222)
     }
     async a()
     {
         try
         {
             var loc = await this.getLocation();
             alert(loc)
         }
         catch (e)
         {
             alert("catch 2")
         }
     }
 }
 new A().a();
  • Result : "catch 2"

Event If I throw an error in getLocation :

  getLocation()
     {
         throw Error("ffffff")
     }

- I get the same result - which is OK.

So where is the problem ?

Well as you know , an error which is thrown asynchronously-non-promised is a different beast :

So this code won't be catched at all:

  getLocation() //bad code from a third party code , third party code
  { 
      return new Promise((v, x) => setTimeout(() =>
      {
          throw Error("ffffff")
      }, 100))
  }

Question :

Regarding the fact that I want to catch errors - is there a better pattern for capturing this ?

Sure I can do :

window.onerror = function () { alert(4)}

But that would be not in order as the flow of .catch(...) or catch(){} , and I won't be able to do actions regarding that specific action that caused error.

Full disclosure:
No real life scenario. Learning purpose .

Upvotes: 1

Views: 328

Answers (3)

Bergi
Bergi

Reputation: 664297

an error which is thrown asynchronously-non-promised is a different beast

Yes. And it must be avoided at all costs. Therefore, never put business code (including trivial things like property accesses) in asynchronous non-promise callbacks. It could throw! It should be obvious that JSON.parse can fail, that a property access can throw when the "object" is null or undefined or a getter is involved, or that a loop can fail when the thing that was supposed to be an array has no .length.

The only things that are allowed as asynchronous non-promise callbacks are resolve, reject, and (err, res) => { if (err) reject(err); else resolve(res); } (and maybe a variadic version for weird APIs with multiple arguments).

So rewrite the bad code to

async getLocation() {
    await new Promise(resolve => setTimeout(resolve, 100));
    throw Error("ffffff");
}

or

getLocation() {
    return new Promise(resolve => setTimeout(resolve, 100)).then(res => {
        throw Error("ffffff");
    });
}

and when it's third-party code make them fix it, make an upstream merge request of your fix, or if those don't work abandon that party.

is there a better pattern for capturing this?

Well, domains (in node) were supposed to solve this problem of non-locality of asynchronous (uncaught) exceptions, but they didn't work out. Maybe some day, zones with better native language support will replace them.

Upvotes: 2

bluehipy
bluehipy

Reputation: 2294

I guess the basic usage would be like this:

class A {
  getLocation(x) {
    return new Promise((resolve, reject) => setTimeout(() => {
      // a lot of async code
      try {
        //simulate unexpected exception    
        if (x === 2) {
          throw ("code error");
        }
        if (x) {
          resolve('success');
        } else {
          reject('conditional rejection');
        }
      } catch (ex) {
        reject(ex);
      }
    }, 1000));
  }
  async a(x) {
    await this.getLocation(x).then((loc) => console.info(loc)).catch((e) => console.error(e));
  }
}
let o = new A();
o.a(2);
o.a(0);
o.a(1);

The rejection of the Promise is not necessarily an code Exception as well as the code Exception should not necessarily trigger a Promise rejection.

Upvotes: 0

Estus Flask
Estus Flask

Reputation: 222334

The errors should be caught in place where they occur.

This kind of code code is incorrect and should be fixed in-place:

  getLocation() //bad code from a third party code
  { 
      return new Promise((v, x) => setTimeout(() =>
      {
          throw Error("ffffff")
      }, 100))
  }

If this is third-party code, it can be forked or patched.

Exceptions can be tracked globally by onerror, as the question already mentions. This should be used only to notify a developer of existing errors, not to handle them in normal way.

unhandledrejection event can be used for same purpose to notify about unhandled rejections in promises. It won't be able to handle the error in the snipped above because it is thrown inside setTimeout callback and doesn't result in promise rejection.

Upvotes: 0

Related Questions