Skip to content

Instantly share code, notes, and snippets.

@tjunghans
Last active May 9, 2017 12:58
Show Gist options
  • Save tjunghans/dcc5bf996885f388fd4deb976c403173 to your computer and use it in GitHub Desktop.
Save tjunghans/dcc5bf996885f388fd4deb976c403173 to your computer and use it in GitHub Desktop.
Promise Error Handling

Promise Error Handling

  • Errors can be handled in a synchronouse fashion
  • You can throw an exception in a Promise
  • You can reject a promise with an exception
  • You can catch an exception with Promise catch

Throwing and Rejecting Errors

Example 1: Throwing an Error

const p = new Promise((resolve, reject) => {
  throw new Error("TypeError");
});

Result Example 1

Uncaught (in promise) Error: TypeError

Example 2: Rejecting an Error

const p = new Promise((resolve, reject) => {
  reject(new Error("TypeError"));
});

Result Example 2

Uncaught (in promise) Error: TypeError

Handling an Error

Example 1: Catching an exception

const p = new Promise((resolve, reject) => {
  throw new Error("TypeError");
});
p.catch(err => {
  console.log(err);  
})

Result Example 1

Logs the error as expected:

Error: TypeError
...

Example 2: Catching a rejected error

const p = new Promise((resolve, reject) => {
  reject(new Error("TypeError"));
});
p.catch(err => {
  console.log(err);  
})

Result Example 2

Logs the error as expected:

Error: TypeError
...

Conclusion of handling errors

reject(new Error("TypeError")); and throw new Error("TypeError"); can be handled the same way with catch.

Errors in a Promise Chain

Example 1: Promise 2 will execute, Exception is caught

const p1 = new Promise((resolve, reject) => {
  reject(new Error("TypeError")); // or "throw new Error("TypeError");"
});

const p2 = new Promise((resolve, reject) => {
  console.log("Promise 2"); // logs "Promise 2" which one may not expect
  return "Promise 2";
});

// Without this catch, an uncaught exception is thrown
p1.then(p2).catch(err => {
  console.log(err);  // logs "Error: TypeError"
}).then(res => {
  console.log(res);  // This is logged with `undefined`
});

Example 2: Promise 4 (3rd wrapper) will NOT execute, Exception is caught

let counter = 0;

function wrapper(error) {
  return counter => {
    return new Promise(resolve => {
      console.log(counter);
      if (error) {
         throw new Error("TypeError");
      }
      setTimeout(() => {
        resolve(counter + 1);
      }, 1); 
    });
  };
}


const p0 = Promise.resolve(counter);

p0.then(wrapper()).then(wrapper()).then(wrapper(true)).catch(err => {
  console.log(err);  
}).then(res => {
  console.log(res);  
});

Example 3: Promise Chain with error

const counter = 0;

function createPromise(error) {
  return counter => {
    return new Promise(resolve => {
      console.log("Counter", counter);
      if (error) {
         throw new Error("TypeError");
      }
      resolve(counter + 1);
    });
  };
}

Promise.resolve(counter).then(createPromise()).then(createPromise()).then(createPromise(true)).then(res => {
  console.log("Success", res);  // not logged
}).catch(err => {
  console.log("Fail", err);  // logged
});

Log output

Counter 0
Counter 1
Counter 2
Fail Error: TypeError
    at resolve (<anonymous>:11:16)
    at counter (<anonymous>:8:12)

Take note, "Success" was not logged.

Using the above example, if one swaps the final catch and then statements, both "Success" and "Fail" will be logged.

Example 4: Promise Chain with error with final then after catch

const counter = 0;

function createPromise(error) {
  return counter => {
    return new Promise(resolve => {
      console.log("Counter", counter);
      if (error) {
         throw new Error("TypeError");
      }
      resolve(counter + 1);
    });
  };
}

Promise.resolve(counter).then(createPromise()).then(createPromise()).then(createPromise(true)).catch(err => {
  console.log("Fail", err);  // logged
}).then(res => {
  console.log("Success", res);  // also logged, with undefined
});

Log output

Counter 0
Counter 1
Counter 2
Fail Error: TypeError
    at resolve (<anonymous>:11:16)
    at counter (<anonymous>:8:12)
Success undefined    

Example 5: Promise Chain with no errors

const counter = 0;

function createPromise(error) {
  return counter => {
    return new Promise(resolve => {
      console.log("Counter", counter);
      if (error) {
         throw new Error("TypeError");
      }
      resolve(counter + 1);
    });
  };
}

Promise.resolve(counter).then(createPromise()).then(createPromise()).then(createPromise()).catch(err => {
  console.log("Fail", err);  // not logged
}).then(res => {
  console.log("Success", res);  // logged, with 3
});

Log output

Counter 0
Counter 1
Counter 2
Counter 2
Success 3    

DRAFT BELOW

// Example made to run in console
// Example inspired by https://medium.com/@arthurxavier/error-handling-in-long-promise-chains-155f610b5bc6

console.clear();

// this would typicall do something async
// id is just an identifier or label for the call
// error, if set to true will cause the promise to reject
function makeApiCall(id, error = false) {
    if (error) {  
    console.log("reject", id); 
        return Promise.reject(new Error("apiCallError", id));
    }
    console.log("success", id);
    return Promise.resolve(id);
}

function uploadImages() {
    return makeApiCall("uploadImages").catch(err => Promise.reject("uploadimages"));
}

function saveService() {
    return makeApiCall("saveService", true).catch(err => Promise.reject("saveService"));
}

function savePricingInfo() {
    return makeApiCall("savePricingInfo").catch(err => Promise.reject("savePricingInfo"));
}

function saveApp() {
    return makeApiCall("saving app...");
}

saveApp()
.then(uploadImages)
.then(saveService)
.then(savePricingInfo)
.then(id => {
  // will only be called if there are no rejects in the chain above
  console.log("full success");
})
.catch(id => {
  // will be called if there is one or more rejects in the promise chain
  console.log("caught", id);
});

Helpful Promise Ressources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment