2

I am completely new to Promises and async/await and just reading through tutorials etc., so I expect I may be missing something fundamental.

I've see this code pattern in several places, but I'm thinking maybe it should not be trusted:

async function myFunc() {
  try {
      var result = await doSomethingAsync();
      console.log(result);
  } 
  catch(error) {
      console.error(error); // hmm
  }
}

myFunc();

Consider the following scenario using the above pattern:

const doSomethingAsync = behaviour => new Promise((resolve, reject) => {  
    // use setTimeout to simulate e.g. an async webapi callback func
    setTimeout(() => {                             
        if(behaviour === "set resolve") 
            resolve("resolved");
        if(behaviour === "set reject") 
            reject("rejected");
        if(behaviour === "set after timeout error") 
            throw new Error("something went wrong after setTimeout returned");
    }, 500);

    if(behaviour === "set promise error")
        throw new Error("something went wrong in promise");
});

async function myFunc(behaviour) {
  try {
        // wait for promise to complete
        var result = await doSomethingAsync(behaviour);
        console.log(result);
  } 
  catch(error) {
      console.error("caught:" + error); // will catch reject and promise error, 
                                        // but NOT after setTimeout error
  }
}

myFunc("set promise error");  // caught:Error: something went wrong in promise 
myFunc("set resolve"); // resolved 
myFunc("set reject"); // caught:rejected 
myFunc("set after timeout error"); // Uncaught Error: something went
                                   // wrong after setTimeout returned
                                   // UHOH!!

So the pattern seems a little misleading as it cannot catch the setTimeout error, whereas people tend to think of catch() as a catch-all.

Of course, changing the setTimeout to have an internal catch will solve the uncaught error problem:

const doSomethingAsync = behaviour => new Promise((resolve, reject) => {  
    // use setTimeout to simulate e.g. an async webapi call
    setTimeout(() => {            
        try { // ... 
        }
        catch(e) { reject("an error"); }
    }, 500);
});

So, my questions are:

  1. As I understand it, Promises are used as a replacement for callbacks, i.e. for wrapping async calls like setTimeout. So should there always be an internal try/catch -> reject pattern implemented inside a Promise? (So that the error can be gracefully handled by the caller). Do e.g. all node libraries work in this way? I can't see any way for the caller to deal with it by itself.

  2. I find the pattern misleading, wouldn't the pattern be better like this?

    async function myFunc(behaviour) {
      try {
            var result = await doSomethingAsync(behaviour);
                            .catch(e) { console.log("expected reject happened:" + e) };
      } 
      catch(error) {
          console.error("something totally unexpected happened:" + error); 
      }
    }
jimasp
  • 962
  • 9
  • 26
  • 3
    The `catch` pattern is fine, the problem is throwing an exception from `setTimeout` in the first place. That simply shouldn't be done when using promises (and not with callbacks either), you should `throw` only in `then` callbacks. – Bergi Jan 22 '19 at 14:21
  • 1
    No, you don't need both `….catch()` and `try { await … } catch() {}`. – Bergi Jan 22 '19 at 14:22
  • Thanks, clearly my stackoverflow searching is rusty, never saw those dupes. I guess that's kinda the point in keeping dupes though, makes the answer easier to find. I've upvoted your other answers. – jimasp Jan 22 '19 at 15:36
  • Well I didn't find them through the search either, they're in my bookmarks :-) Glad they answer your questions! – Bergi Jan 22 '19 at 15:37

0 Answers0