- 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
const p = new Promise((resolve, reject) => {
throw new Error("TypeError");
});
Uncaught (in promise) Error: TypeError
const p = new Promise((resolve, reject) => {
reject(new Error("TypeError"));
});
Uncaught (in promise) Error: TypeError
const p = new Promise((resolve, reject) => {
throw new Error("TypeError");
});
p.catch(err => {
console.log(err);
})
Logs the error as expected:
Error: TypeError
...
const p = new Promise((resolve, reject) => {
reject(new Error("TypeError"));
});
p.catch(err => {
console.log(err);
})
Logs the error as expected:
Error: TypeError
...
reject(new Error("TypeError"));
and throw new Error("TypeError");
can be handled the same way with catch
.
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`
});
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);
});
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
});
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.
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
});
Counter 0
Counter 1
Counter 2
Fail Error: TypeError
at resolve (<anonymous>:11:16)
at counter (<anonymous>:8:12)
Success undefined
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
});
Counter 0
Counter 1
Counter 2
Counter 2
Success 3
// 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);
});