Javascript Catch In Then Promises - javascript

I am trying to figure this out. I have a promise like this
function Function1 () {
return fetch()
.then((xx) => )
.catch(error => throw(error));
}
Use this Function1 promise in another file.
Function1()
.then((xx) => ()
.catch((error) => {
console.log('I want to Catch that stupid error here');
});
Why can't I get the error message thrown from the Function1 promise in the catch error where I am calling this Function1() ?
Any of your kind help and comments will be highly appreciated, Gracious :)

Use throw inside .then function.
// Here is Promise then throw example
new Promise((resolve, reject) => {
resolve(5);
}).then(result => {
throw 'Err';
})
.catch(error => {
console.log(error);
throw error;
});

Related

Promise rejection not getting catched

Why is a promise rejection not catched here? I tried to debug it but reason never gets executed
axios.post('http://localhost:5000/', {
contractId: contractValue
}).then(() => {
setLoading(false)
setButton(null)
}, (reason) => {
console.log(reason)
})
Instead try putting a catch in your promise chain. It will catch any exceptions in the chain before it. It would look something like this:
axios.post('http://localhost:5000/', {
contractId: contractValue,
})
.then(() => {
setLoading(false)
setButton(null)
})
.catch(err => {
// this is where you handle your exception
console.log(err)
})
Instead of passing the function as a second argument, you can add the .catch block that will handle all exceptions when thrown
axios.post('http://localhost:5000/', {
contractId: contractValue
}).then(() => {
setLoading(false)
setButton(null)
}).catch((reason) => {
console.log(reason)
})
onRejected never handles rejected promises from the same .then(onFulfilled) callback and .catch takes both.
const getPromise = () => new Promise((resolve, reject) => { Math.round(Math.random()) ? resolve('resolve #1') : reject('reject #1')})
getPromise().then(result => { throw new Error('reject #2')}, error => { // Handles only 'reject #1'})
getPromise().then(result => { throw new Error('reject #2')}) .catch(error => { // Handles both 'reject #1', // and 'reject #2' }))
Above description was from this link: The real difference between catch vs onRejected

Promise.reject in .then() returning undefined

I've currently got an ES6 class with a constructor and two methods. I'm a tad confused as to why using Promise.reject(ex) within the .then() is resolving undefined. If someone wouldn't mind explaining what I'm doing wrong that would be much appreciated.
I have a method called getYaml() which contains the following:
_getYaml(recordId) {
return new Promise((resolve, reject) => {
fs.readFile(this.workingDir + '/' + recordId + '.yaml', 'utf8', function(err, data) {
if (err) reject(err)
resolve(data)
})
})
}
I then have another method called getCompDoc which makes use of the other method like so:
getCompDoc(recordId) {
return this._getYaml(recordId).then(data => {
let yaml = data
let yamlObj
try {
yamlObj = YAML.safeLoad(yaml)
} catch (ex) {
ex.message = `Failure to parse yaml. Error: ${ex.message}`
logger.error(ex.message, {}, ex)
return Promise.reject(ex)
}
let compDoc = {
// ...
}
return compDoc
}).catch(err => {
logger.error(err, {}, err)
})
}
I then have a test to check that the YAML parsing error is caught and then a promise rejected which looks like so:
describe('error cases', () => {
const fakeRecordId = 'SomeYaml'
beforeEach(() => {
sinon.stub(myClass, '_getYaml').returns(Promise.resolve('{{&^%}egrinv&alidgj%^%^&$£#£#£}'))
})
afterEach(() => {
myClass._getYaml.restore()
})
it('Error parsing yaml, rejects with error', () => {
return expect(myClass.getCompDoc(fakeRecordId)).to.be.rejected.then(response => {
expect(response.message).to.match(/Failure to parse yaml. Error: /)
})
})
})
Test output:
AssertionError: expected promise to be rejected but it was fulfilled with undefined
If I simply return the exception that is thrown within the getCompDoc method, I recieve the error as expected, however as soon as I use Promise.reject it resolves with undefined.
I was thinking of wrapping the getCompDoc in a return new Promise() however I wasn't sure if this would be an example of the Promise constructor anti-pattern. I would ideally like to reject this, instead of returning the error directly as then I can assert that the method was rejected and not fulfilled.
You 'swallow' the error in getCompDoc in your catch clause. Specifically, here's a simplified snippet representing your code:
let getYamlPromise = Promise.reject('REJECTED!');
let getCompDocPromise = getYamlPromise
.then(data => console.log('getYamlPromise', data))
.catch(error => console.error('getYamlPromise', error));
getCompDocPromise
.then(a => console.log('getCompDocPromise RESOLVED', a))
.catch(a => console.log('getCompDocPromise REJECTED', a));
As you can see, getCompDocPromise is resolved with undefined. If you would like to propagate the error, your catch clause will have to throw a new error or return a rejected promise:
let getYamlPromise = Promise.reject('REJECTED!');
let getCompDocPromise = getYamlPromise
.then(data => console.log('getYamlPromise', data))
.catch(error => {
console.error('getYamlPromise', error);
return Promise.reject(error);
});
getCompDocPromise
.then(a => console.log('getCompDocPromise RESOLVED', a))
.catch(a => console.log('getCompDocPromise REJECTED', a));

Catch error in promise from a service in an Angular component

Hi everyone running into a problem with a post service I created in angular. Struggling to catch the error from my component when I call the service. I was able to catch the error from the service but I need to do this from my component to properly handle the error. Any advice would be greatly appreciated.
Service
sendData(obj) {
let promise = new Promise((resolve) => {
this.http.post(this.URL, obj, this.httpOptions)
.toPromise()
.then(
res => {
console.log(res);
resolve(res);
}
)
//.catch((err) => {
// console.log(err);
// throw err;
//});
});
return promise;
}
Component
this._myservice.sendData(this.myobj)
.then(function (res) {
console.log('data sent');
})
.catch(error => {
console.warn('from component:', error);
// this console warn never gets logged out
});
Do I need to update something in my service to allow me to catch the error from the component?
You're creating your own Promise here, but you never call reject if the Promise you're wrapping rejects (throws an error). This is known as the the new Promise antipattern. In your case, you can simply remove this wrapper and replace the call to resolve with a return in order to achieve what you need, like so:
sendData(obj) {
return this.http.post(this.URL, obj, this.httpOptions)
.toPromise()
.then(res => {
console.log(res);
return res;
});
}
In order to provide more context, you could fix your original problem by calling reject. This would look like this:
// DONT'T DO THIS
sendData(obj) {
let promise = new Promise((resolve, reject) => {
this.http.post(this.URL, obj, this.httpOptions)
.toPromise()
.then(res => {
console.log(res);
resolve(res);
})
.catch((err) => {
console.log(err);
reject(err); // Here.
});
});
return promise;
}
But, as I said above, this is overcomplicated and unnecessary. I hope that it demonstrates how the Promise your component has access to could never see errors that occurred in the HTTP call.

Promise chain with an asynchronous operation not executing in order

I have found other people asking about this topic but I haven't been able to get my promise chain to execute in order.
Here is a basic reproduction of what is happening:
function firstMethod(){
dbHelper.executeQuery(queryParameters).then(result => {
if (result === whatIAmExpecting) {
return dbHelper.doDbOperation(secondQueryParameters)}
else {
throw new Error('An error occurred')
}})
.then(doFinalOperation())
.catch(error => {
})
}
In the above code doFinalOperation() is called before the then function after executeQuery() is called.
Here is the implementation of executeQuery():
function executeQuery(parameter) {
return new Promise((resolve, reject) => {
const queryToExecute = `SELECT * FROM parameter`
return mySqlConnection.query(queryToExecute).then((result) => {
resolve(result)
}).catch(error => {
reject(error)
})
})
And here is the implementation of of the mySqlConnection.query method:
function query(queryString){
return new Promise((resolve, reject) =>
{
initConnection()
connection.connect()
require('bluebird').promisifyAll(connection)
return connection.queryAsync(queryString).then(function(results) {
connection.end();
resolve(results)
}).catch(error => {
reject(error)
})
})
It seems like I have incorrectly implemented the executeQuery() method. The database operation in the mySqlConnection.query is asychronous and I can see that's where the chain of promises stops happening in the expected order.
My question in a nutshell: How do I make the my chain of promises execute in order, and how I do stop a then() method from being executed before the previous Promise has called resolve() or reject()?
Thanks in advance.
then expects a function, but you have accidentally executed it, instead of passing it. Change:
then(doFinalOperation())
with:
then(doFinalOperation)
Now it will be the promise implementation that invokes it (at the proper time), not "you".
If your function needs arguments to be passed, then you can either
(1) Use bind:
then(doFinalOperation.bind(null, parameterOne, parameterTwo, parameterThree))
(2) Use a function expression
then(_ => doFinalOperation(parameterOne, parameterTwo, parameterThree))
Both your .then() methods get called on the first async operation...
Should be something like this:
function firstMethod(){
dbHelper.executeQuery(queryParameters).then(expectedResult => {
if (expectedResult === whatIAmExpecting) {
return dbHelper.doDbOperation(secondQueryParameters)}
.then(doFinalOperation())
.catch(error => {
};
}
else {
throw new Error('An error occurred')
}})
.catch(error => {
});
}

TypeScript error TS2345 when rejecting a Promise with an error

I have a TypeScript error message whose error I do not understand. The error message is:
error TS2345: Argument of type '(error: Error) => void | Promise' is not assignable to parameter of type '(reason: any) => IdentityKeyPair | PromiseLike'.
Type 'void | Promise' is not assignable to type 'IdentityKeyPair | PromiseLike'.
My code was working fine but TypeScript got mad at me when I changed this block:
.catch((error) => {
let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
return this.store.save_identity(identity);
})
into this:
.catch((error) => {
if (error instanceof RecordNotFoundError) {
let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
return this.store.save_identity(identity);
} else {
return reject(error);
}
})
Here is the complete code which was working:
public init(): Promise<Array<Proteus.keys.PreKey>> {
return new Promise((resolve, reject) => {
this.store.load_identity()
.catch((error) => {
let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
return this.store.save_identity(identity);
})
.then((identity: Proteus.keys.IdentityKeyPair) => {
this.identity = identity;
return this.store.load_prekey(Proteus.keys.PreKey.MAX_PREKEY_ID);
})
.then((lastResortPreKey: Proteus.keys.PreKey) => {
return resolve(lastResortPreKey);
})
.catch(reject);
});
}
And here is the code which does not compile anymore:
public init(): Promise<Array<Proteus.keys.PreKey>> {
return new Promise((resolve, reject) => {
this.store.load_identity()
.catch((error) => {
if (error instanceof RecordNotFoundError) {
let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
return this.store.save_identity(identity);
} else {
return reject(error);
}
})
.then((identity: Proteus.keys.IdentityKeyPair) => {
this.identity = identity;
return this.store.load_prekey(Proteus.keys.PreKey.MAX_PREKEY_ID);
})
.then((lastResortPreKey: Proteus.keys.PreKey) => {
return resolve(lastResortPreKey);
})
.catch(reject);
});
}
Does anyone sees why the TypeScript compiler refuses my return reject(error); statement with error code TS2345?
Screenshot:
I am using TypeScript 2.1.4.
Try out below. When you are in a then or catch block you can return a Promise or a value which gets wrapped into a Promise. You are manually working with a Promise yourself so you can just call the resolve and reject handlers without needing to return anything. Returning reject(error) would try to take that returned value, wrap it in a Promise and then try to pass to the next then block which is why you were getting the error you did. Think of it this way: returning something in a handler means continue down the chain with this new value. In your case I think you just want to stop the chaining and have the Promise you are creating resolve or reject under certain conditions.
public init(): Promise<Array<Proteus.keys.PreKey>> {
return new Promise((resolve, reject) => {
this.store.load_identity()
.catch((error) => {
if (error instanceof RecordNotFoundError) {
let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
return this.store.save_identity(identity);
} else {
throw error;
}
})
.then((identity: Proteus.keys.IdentityKeyPair) => {
this.identity = identity;
return this.store.load_prekey(Proteus.keys.PreKey.MAX_PREKEY_ID);
})
.then((lastResortPreKey: Proteus.keys.PreKey) => {
resolve(lastResortPreKey);
})
.catch((error) => {
reject(error);
});
});
}
You can't stop a Promise chain (cancellation aside), not even by returnning reject(), which is a definite misuse of Promises (you're not supposed to wrap a Promise in another Promise constructor).
Let's start with what you could do, then go to what you should do.
You could let the rejection bubble down the Promise chain, rethrowing it when it doesn't match your type guard, and at the bottom of the line, after all the .catch() clauses exhausted themselves, the Promise returned from your function will reject.
Now
Think about how you would do it in sync code. You'd have something like this:
try {
try {
actionThatThrows();
} catch (err) {
breakEverything();
}
continue other steps
} catch(err) {
generalErrorHandling();
}
That kind of code is not OK, and it isn't OK in Promises either. You should move distinct actions into functions which can resolve or reject on their own, use Errors as they were meant, an exception that bubbles up the stack until it meets something that can handle it.
Also, and because you're using TS 2.1.x, for long async flows, an async function is recommended.
Your return is useless there, it's the end of the onRejection callback.
And the return reject() will fulfill the next .then() promise anyway.
However, if you throw the error, it'll be inherited in the following promises down to the .catch(reject);
Basically: in any catch/then, return will resolve the child promise, and throw will reject the child promise.
I rewrote your code for a better flow of the promise chain.
public init(): Promise<Array<Proteus.keys.PreKey>> {
return new Promise((resolve, reject) => {
this.store.load_identity()
.catch(
(error) => {
if (error instanceof RecordNotFoundError) {
let identity: Proteus.keys.IdentityKeyPair = Proteus.keys.IdentityKeyPair.new();
return this.store.save_identity(identity);
} else {
throw error;
}
}
)
.then(
(identity: Proteus.keys.IdentityKeyPair) => {
this.identity = identity;
resolve(this.store.load_prekey(Proteus.keys.PreKey.MAX_PREKEY_ID));
},
reject
)
});
}

Categories

Resources