Chained promises won't catch an error - javascript

I'm trying to make promises work, and so far i've stumbled on this:
new Promise((resolve, reject) => {
setTimeout(() => {
return resolve()
}, 400)
}).then(new Promise((resolve, reject) => {
setTimeout(() => {
return reject('some error')
}, 100)
})).then(() => {
console.log('All promises resolved')
}).catch((err) => {
console.log('Error: ' + err)
})
My understanding is that this example should display Error: some error, with the first promise successfully resolving, and the second one throwing an error. But when i run this (in node 9.7, if that matters) i get this error:
(node:10102) UnhandledPromiseRejectionWarning: some error
(node:10102) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:10102) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
All promises resolved
My .catch() doesn't seem to be working, is there a problem with it ?

You are actually passing promise, instead of function.
You should write your code like this:
new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 400)
}).then(() => new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('some error'))
}, 100)
})).then(() => {
console.log('All promises resolved')
}).catch((err) => {
console.log('Error: ' + err)
})

Related

UnhandledPromiseRejectionWarning: Reject an unhandled promise when processing certain cases with the question

I have this question that addresses a bunch of cases:
Your function must always return a promise
If data is not a number, return a promise rejected instantly and give the data "error" (in a string)
If data is an odd number, return a promise resolved 1 second later and give the data "odd" (in a string)
If data is an even number, return a promise rejected 2 seconds later and give the data "even" (in a string)
I typed the code for the question, but I got this error:
(node:6) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ReferenceError: data is not defined
(node:6) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
This is the code:
const job = new Promise((resolve, reject)=>{
if(isNaN(data)){
reject('erroe')
}
else if(isNaN(data) && data%2!=0){
setTimeout(function(){
resolve('odd')
} , 1000)
}
else {
setTimeout(function(){
reject('even')
}, 2000)
}
})
module.exports = job;
Here's what you can do in a concise way:
const job = data => new Promise((resolve, reject) =>
typeof(data) === "number"
? setTimeout(() => resolve(data % 2 ? 'odd' : 'even'), 1000)
: reject("error"))
job("s")
.then(result => console.log(result))
.catch(error => console.log(error));
job(5)
.then(result => console.log(result))
.catch(error => console.log(error))
job(2)
.then(result => console.log(result))
.catch(error => console.log(error))

Promise.all causes Jest to display UnhandledPromiseRejectionWarning

I have some code which calls Promise.all. It runs OK in the browser with no warnings in the console.
There are 3 functions f1, f2 & f3 all of which return a promise. The code looks like this
Promise.all([
f1(),
f2(),
f3()
]).then((values) => {
resolve({success: true})
}).catch(err => {
reject(err)
})
When I use Jest to test the file containing the above code I see this error.
(node:17177) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 18)
Is this the wrong way to code the above or is it a bug within Jest?
Here's the actual code that I'm using:
getDataFromDatabase() {
return new Promise((resolve, reject) => {
const assessmentUrl = `${this.assessmentUrl}`
http.get(assessmentUrl).then(response => {
if (response.data.record === null) {
Promise.all([
this._getPupilPlacement(),
this._getSurveyQuestions(),
this._getCompetencies()
]).then((values) => {
successState.pupilPlacement = values[0].pupilPlacement
successState.items = values[1].items
successState.formid = values[2].formid
successState.competencies = values[3].competencies
const panels = this.getPanels(values[3].competencies)
successState.panels = panels
successState.numPages = panels.length
successState.itemsAreOverridden = true
resolve(successState)
}).catch(err => {
reject(err)
})
}
else {
resolve(response.data.record)
}
})
})
}
Avoid the Promise constructor antipattern! You were forgetting to handle errors from the http.get(assessmentUrl) promise.
You should be writing
getDataFromDatabase() {
const assessmentUrl = `${this.assessmentUrl}`
return http.get(assessmentUrl).then(response => {
//^^^^^^
if (response.data.record !== null)
return response.data.record;
return Promise.all([
// ^^^^^^
this._getPupilPlacement(),
this._getSurveyQuestions(),
this._getCompetencies()
]).then(values => {
const panels = this.getPanels(values[3].competencies)
return {
// ^^^^^^
pupilPlacement: values[0].pupilPlacement,
items: values[1].items,
formid: values[2].formid,
competencies: values[3].competencies,
panels: panels,
numPages: panels.length,
itemsAreOverridden: true,
};
});
});
}
Explanation:
Calling reject will throw an error. If your top level promise doesn't catch it, then well it's an unhandled promise.
MDN Image src
Solution:
getDataFromDatabase().catch(err=>console.lor(err.message));
Example of a promise that rejects.:
function getDataFromDatabase(){
return Promise.reject(123);
}
getDataFromDatabase()
.then(data=>console.log("Success " + data))
.catch(err=>console.log("Error " + err));
Promise MDN doc
Future recommendation:
For every child promise you seem to be adding a .catch() which isn't needed. As long as somewhere higher up there is a catch, then the promise will be handled.

Why I get the "(node:7424) UnhandledPromiseRejectionWarning" message for handled error?

I handle the error in my Promise by catch, but in Node.js (v10.11.0) console output I see the message: (node:7424) UnhandledPromiseRejectionWarning: Error: Oops...
Why does it happen?
// See browser console, not stack snippet console, to see uncaught error
const p = new Promise((resolve,reject) => { throw new Error('Oops..');});
p.then(()=> console.log('Then'));
p.catch(err => console.log(err.message)); // the error handling
console.log('The end');
Also, I get the same result for such variant of p initializing:
const p = new Promise((resolve,reject) => { reject(new Error('Oops..'));});
This is my output:
The end
Oops..
(node:7492) UnhandledPromiseRejectionWarning: Error: Oops..
Whenever you call .then (or .catch) on an existing Promise, you have a new Promise. The error results from the Promise chain created by
p.then(()=> console.log('Then'));
not being caught anywhere.
Either chain the .catch onto the .then:
const p = new Promise((resolve, reject) => {
throw new Error('Oops..');
});
p
.then(() => console.log('Then'))
.catch(err => console.log(err.message));
console.log('The end');
Note that when constructing a Promise, it's a good idea to always call reject explicitly when there's an error, to ensure that the consumer of that Promise can catch problems. For example, in the following code, the p will not be rejected, and will remain unresolved forever, because the error was thrown asynchronously:
const p = new Promise((resolve, reject) => {
setTimeout(() => {
throw new Error('Oops..');
});
})
p
.then(() => console.log('Then'))
.catch(err => console.log(err.message))
console.log('The end');
Better to call reject:
const p = new Promise((resolve, reject) => {
setTimeout(() => {
reject('Oops..');
});
})
p
.then(() => console.log('Then'))
.catch(err => console.log(err))
console.log('The end');

Promise rejection throws warning even if it's being caught later [duplicate]

This question already has answers here:
Prevent "Unhandled promise rejection" error
(3 answers)
Closed 4 years ago.
Example
class Foo {
private pro = new Promise(() => {
throw new Error();
});
public usePro() {
return this.pro.then(() => {});
}
}
let foo = new Foo();
setTimeout(() => {
foo.usePro().then(() => {
console.log("end.");
}).catch(() => {
console.log("error.");
})
}, 1000);
I understand that javascript can't know at runtime that someone will catch the error later, so how am I suppose to do in such a situation ?
Console
(node:39166) UnhandledPromiseRejectionWarning: error
(node:39166) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:39166) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
error.
(node:39166) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
Errors should be caught wherever the Promise is used, even if that Promise is returned (and caught) by something else later. One option would be to assign to this.proValue a resolved object or a rejected object, depending on whether the original Promise resolves or rejects. Then, when usePro is called, check this.proValue and return either Promise.resolve(resolved) or Promise.reject(rejected). Using standard Javascript so this can be shown in a runnable snippet:
class Foo {
constructor() {
this.pro = new Promise(() => {
throw new Error('Problem!');
})
.then((resolved) => {
this.proValue = { resolved };
})
.catch((rejected) => {
this.proValue = { rejected };
});
}
usePro() {
const { resolved, rejected } = this.proValue;
if (resolved) return Promise.resolve(resolved);
else if (rejected) return Promise.reject(rejected);
}
}
const foo = new Foo();
setTimeout(() => {
foo.usePro().then(() => {
console.log("end.");
}).catch((e) => {
console.log("error caught. " + e);
})
}, 1000);
If you want to be able to call usePro before Foo's internal Promise has resolved (or rejected), then when usePro is called, construct and return a Promise that resolves once this.pro's Promise resolves (or rejects). unfortunately the code required is moderately more complicated:
class Foo {
constructor() {
this.callProms = [];
setTimeout(() => {
this.pro = new Promise(() => {
throw new Error('Problem!');
})
.then((resolved) => {
this.proValue = { resolved };
})
.catch((rejected) => {
this.proValue = { rejected };
})
.finally(() => {
console.log('internal promise finishing');
this.resolveCalls();
});
}, 1000);
}
resolveCalls() {
this.callProms.forEach((resolve) => {
resolve(this.getProValue());
});
}
getProValue() {
const { proValue } = this;
if (!proValue) return;
const { resolved, rejected } = proValue;
if (resolved) return Promise.resolve(resolved);
else if (rejected) return Promise.reject(rejected);
}
usePro() {
return this.getProValue()
|| new Promise((resolve) => {
this.callProms.push(resolve);
});
}
}
console.log('Starting');
const foo = new Foo();
// Immediate call of `usePro`:
foo.usePro().then(() => {
console.log("end.");
}).catch((e) => {
console.log("immediate error caught. " + e);
})
// Delayed call:
setTimeout(() => {
foo.usePro().then(() => {
console.log("end.");
}).catch((e) => {
console.log("delayed error caught. " + e);
})
}, 2000);
Great answer by CertainPerformance.
Let me add that in Node.js, you can also add an unhandledRejection listener on process:
process.on('unhandledRejection', reason => {
console.error({Error:reason})
process.exit(1);
});
You could use Promise.all to delay the resolving:
const delay = ms => new Promise(res => setTimeout(res, ms));
Promise.all([
foo.usePro(),
delay(1000)
]).then(() => {
console.log("end.");
}).catch(() => {
console.log("error.");
});
That way the .catch is directly attached, but the then callback is executed after the delay.

node 8.6 javascript promises: UnhandledPromiseRejectionWarning

I am having an error: (node:6186) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): threep
(node:6186) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
-------- ones
========= two
CaughtCathchError threep
(node:6186) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
I am consuming my 3 promise functions in nested order.
p1,p2,p3- are my promise functions as shown below.
i tried adding promise reject in all p1,p2,p3 functions as well but its still the same
enter code here
var p1 = new Promise(function (resolve, reject) {
setTimeout(function () {
// resolve('ones')
resolve('ones')
}, 9000)
})
var p2 = new Promise(function (resolve, reject) {
setTimeout(function () {
// throw new Error('eeeee');
//reject('two')
resolve('two')
}, 1000)
})
var p3 = new Promise(function (resolve, reject) {
setTimeout(function () {
reject('three')
}, 4000)
})
p1.then(function(result){
console.log("--------", result)
// return p2.then(function(res){console.log(res)}).catch(function(err){console.log(err)})
return p2
}).then(function(p2result){
console.log("=========", p2result)
return p3;
}).then(function(p3result){
console.log('*********', p3result)
}).catch(function(err){
console.log("CaughtCathchError", err)
})
p3 is a standalone Promise with no .catch. So, when p3 gets rejected, you get a UnhandledPromiseRejectionWarning. Even if p3 is consumed later in a Promise chain that has a proper catch, p3 itself does not have a catch.
Instead of p3, you might use a function that returns a Promise, and ensure that all calls to that function are caught:
var p1 = new Promise(function (resolve, reject) {
setTimeout(function () {
// resolve('ones')
resolve('ones')
}, 1000)
})
var p2 = new Promise(function (resolve, reject) {
setTimeout(function () {
// throw new Error('eeeee');
//reject('two')
resolve('two')
}, 1000)
})
var getp3 = () => new Promise(function (resolve, reject) {
setTimeout(function () {
reject('three')
}, 1000)
})
p1.then(function(result){
console.log("--------", result)
// return p2.then(function(res){console.log(res)}).catch(function(err){console.log(err)})
return p2
}).then(function(p2result){
console.log("=========", p2result)
return getp3();
}).then(function(p3result){
console.log('*********', p3result)
}).catch(function(err){
console.log("CaughtCathchError", err)
})
If you need to initialize p3 immediately, then put a catch after the p3 itself.
Node.js promise implementation expects rejected promise to be chained with catch(...) or then(..., ...) synchronously, otherwise PromiseRejectionHandledWarning appears. Unhandled promise rejections may result in exception in future.
Usually a rejection should be treated as any other error, so it's preferable for it to be an instance of Error and not plain string. Then it could be treated as such:
class ExpectedRejection extends Error {}
var p3 = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(new ExpectedRejection('three'))
}, 4000)
})
...
.then(function(p3result){
if (p3result instanceof ExpectedRejection)
throw p3result;
console.log('*********', p3result)
}).catch(function(err){
console.log("CaughtCathchError", err)
})
ExpectedRejection class is specific and possibly not needed; could be replaced with Error everywhere because Error resolutions are uncommon.
This solution is not very common because if promises are created at the same time, they don't depend on each other and usually can be handled with Promise.all:
Promise.all([p1, p2, p3])
.then(function(p1result, p2result, p3result){
console.log('*********', p3result)
}).catch(function(err){
console.log("CaughtCathchError", err)
});
Notice that since p1, p2 and p3 are delays that are created at the same time, resulting catch will be triggered after 9 seconds (maximum duration of a delay) in both cases.
If you want to create a rejecting/rejected promise that will be caught on the queue and not on the stack then you could do the following:
var p3 = new Promise(function (resolve, reject) {
setTimeout(function () {
reject('three')
}, 400)
});
//do not warn for p3 rejection but if you use it later (p3.then) or
// return it in a promise chain you will have to catch it again
p3.catch(ignore=>ignore);

Categories