Async method always returning true - javascript

I am implementing a login functionality with firebase and React Native. The handleLogin method is always returning succeed(). If I remove the success(), I get :
[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'result2.failed')]
export default async function login(credentials) {
let result2= succeed();
result2 = await handleLogin(credentials.email, credentials.password);
if(result2.failed()){
return fail({password: "Login failed"});
}
else{
return succeed();
}
}
const handleLogin = async(email,password) => {
auth.signInWithEmailAndPassword(email, password)
.catch(function(error) {
console.log(error);
return fail("failed");
})
return succeed(); // or fail() in which case method always returns fail()
I have also tried using .then() but I keep getting object undefined error if I don't return succeed() or fail() in the end of handleLogin():
auth.signInWithEmailAndPassword(email, password)
.then(function(){return succeed();})
.catch(function(error) {
console.log("we fail"+error);
return fail("failed");
})

Its a known issue of the firebase. Similar thing happened to me on angular code.

I solved the problem by adding a return statement:
return auth.signInWithEmailAndPassword(email, password).then(function(){return succeed();}).catch(function(error) { return fail("Login Attempt Failed\n"+error);})

Related

How to properly use a class method that returns a promise?

I have a method in a class that returns a Firebase user document:
class FirebaseUtils {
async getUserDocument(uid) {
if (!uid) return null
try {
const userDocument = await this.firestore.collection('users').doc(uid).get()
return { uid, ...userDocument.data() }
} catch (error) {
console.error('error getting user document: ', error)
}
}
}
I am getting PromiseĀ {<pending>} when I try to get the result of this function in another file
//need to update userDocument later
const userDocument = firebaseUtils.getUserDocument(uid)
console.log(userDocument) //PromiseĀ {<pending>}
I've tried this as well ascreating an immediatelly invoked function to await the getUserDocument function but that didn't work.
Since async functions return a Promise, you'll need to await or use .then to get the resolved value:
const userDocument = await firebaseUtils.getUserDocument(uid)
console.log(userDocument)
or
firebaseUtils.getUserDocument(uid).then((userDocument) => {
console.log(userDocument)
})
As a side note, you'll probably want to return null after logging the error in the catch, or at least be aware of the fact that the function returns undefined in that case.

Async function Uncaught (in promise) undefined error

I'm trying to do some validations before creating/updating an entry as shown below:
async save(){
return new Promise((resolve, reject)=>{
if(!this.isCampaignValid){
this.handleError()
reject()
}
else{
this.$store
.dispatch('updateCampaign')
.then((res)=>{
resolve()
this.showNotification(res.message, 'success')
})
.catch(error=>{
this.showNotification(error.message, 'error')
reject()
})
}
})
},
the isCampaignValid is a computed value which computes the validity.
If the campaign is not valid, then I'm getting an error in the console as below:
Uncaught (in promise) undefined
The this.handleError() function works too. How can handle this promise error situation?
Just in case handleError() throws, try:
if (!this.isCampaignValid) {
try {
this.handleError()
} catch (e) {
console.error(e);
}
reject()
}
First of all, you don't need to return a promise in an async function. It implicitly returns one, resolving with the value returned by the function or rejecting with the error object if the function throws. Although you could return a promise and JS unpacks it for you, it's unneeded code.
That said, because async returns a promise, you'll have to catch that promise too. Since your first conditional block just throws an error but doesn't catch it, the promise returned by save will reject. You need to handle that rejection.
Here's a simplified version of your code to see where it's happening.
async save(){
if(!this.isCampaignValid){
this.handleError()
// Throwing an error in an async function is equivalent to a reject.
throw new Error('Campaign is not valid') // Here
}
else{
try {
const res = await this.$store.dispatch('updateCampaign')
this.showNotification(res.message, 'success')
} catch (e) {
this.showNotification(error.message, 'error')
}
}
},
// When you call save, catch the error
yourObject.save()
.then(() => {...})
.catch(() => {...})
// If your call is in an async function, you can try-catch as well
try {
await yourObject.save()
} catch(e) {
// It failed.
}

Angular - Map/Catch returning same value but receiving error

Basically, I have this following code:
let currentTime:number = (new Date()).getTime();
return this.authenticationService.login(credential).map(data => {
const token = data.token;
const id = data.id;
sessionStorage.setItem('userData', JSON.stringify({currentTime, token, id}));
return JSON.parse(sessionStorage.getItem('userData'));
}).catch(error => {
sessionStorage.setItem('userData', JSON.stringify({currentTime, error}));
return JSON.parse(sessionStorage.getItem('userData'));
});
As you can see, either the map or the catch methods, are returning the same code. When I reach the the return statement using the map method, everything runs as expected. But when I reach the return at the catch section Angular says: core.js:1598 ERROR TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.. Why this is happening?
As per error message suggests, you should return a promise, or an observable,...
}).catch(error => {
sessionStorage.setItem('userData', JSON.stringify({currentTime, error}));
return Observable.of(JSON.parse(sessionStorage.getItem('userData')));
});

Using mongoose promises with async/await

I'm trying to get the hang of using Mongoose promises with the async/await functionality of Node.js. When my function printEmployees is called I want to save the list of employees which are queried by the orderEmployees function. While, the console.log statement inside orderEmployees returns the expected query, the console.log inside of printEmployees returns undefined, suggesting that I'm not returning the promise correctly.
I'm new to promises so entirely possible that I'm not correctly understanding the paradigm... any help is much appreciated.
printEmployees: async(company) => {
var employees = await self.orderEmployees(company);
// SECOND CONSOLE.LOG
console.log(employees);
},
orderEmployees: (companyID) => {
User.find({company:companyID})
.exec()
.then((employees) => {
// FIRST CONSOLE.LOG
console.log(employees);
return employees;
})
.catch((err) => {
return 'error occured';
});
},
In order to make orderEmployees behave like async functions, you have to return the resulting promise. There are two rules to follow when using promises without async/await keywords:
A function is asynchronous if it returns a Promise
If you have a promise (for example returned by an async function) you must either call .then on it or return it.
When you are using async/await then you must await on promises you obtain.
This said you will notice that you do not return the promise generated inside orderEmployees. Easy to fix, but its also easy to rewrite that function to async too.
orderEmployees: (companyID) => {
return User.find({company:companyID}) // Notice the return here
.exec()
.then((employees) => {
// FIRST CONSOLE.LOG
console.log(employees);
return employees;
})
.catch((err) => {
return 'error occured';
});
},
or
orderEmployees: async(companyID) => {
try {
const employees = await User.find({company:companyID}).exec();
console.log(employees);
return employees;
} catch (err) {
return 'error occured';
}
},
PS: the error handling is somewhat flawed here. We usually do not handle errors by returning an error string from a function. It is better to have the error propagate in this case, and handle it from some top-level, UI code.
You need to return your Promise.
Currently, you are awaiting on a function that returns undefined.
await only actually "waits" for the value if it's used with a Promise.
Always keep in mind that you can only await Promises or async functions, which implicitly return a Promise1.
orderEmployees: (companyID) => {
return User.find({ company:companyID }).exec()
}
Also really important, you should throw instead of return in your .catch handler. Returning from within a .catch handler will cause the promise chain to trigger it's .then instead of it's .catch thus breaking the error handling chain.
Better yet, don't include .catch at all and let the the actual error bubble up the promise chain, instead of overriding it with your own non-descriptive 'error occured' message.
Error conditions should throw the error, not return it.
1 You can also await non-Promises, but only for values that are evaluated synchronously.
You are not returning a Promise from orderEmployees.
printEmployees: async(company) => {
var employees = await self.orderEmployees(company);
// SECOND CONSOLE.LOG
console.log(employees);
},
orderEmployees: (companyID) => {
return User.find({company:companyID})
.exec()
.then((employees) => {
// FIRST CONSOLE.LOG
console.log(employees);
return employees;
})
.catch((err) => {
return 'error occured';
});
},
You need to return a Promise from orderEmployees
orderEmployees: companyId => User.find({ companyId }).exec()
If you want to do some error handling or pre-processing before you return then you can keep your code as is but just remember to return the result (promises are chainable).
if you're going to use async/await then it works like this.
await in front of the function that returns a promise.
async in front of the wrapping function.
wrap the function body inside try/catch block.
Please have a look on this function, it is a middleware
before i execute a specific route in express.
const validateUserInDB = async (req, res, next) => {
try {
const user = await UserModel.findById(req.user._id);
if (!user) return res.status(401).json({ message: "Unauthorized." });
req.user = user;
return next();
} catch (error) {
return res.status(500).json({ message: "Internal server error." })
}
}
The code after await is waiting the promise to be resolved.
Catch block catches any error happened inside the try block even if the error that is triggered by catch method comes from awaiting promise.

Async function always return undefined

im using nodejs 8. I've replaced promise structure code to use async and await.
I have an issue when I need to return an object but await sentence resolve undefined.
This is my controller method:
request.create = async (id, params) => {
try {
let request = await new Request(Object.assign(params, { property : id })).save()
if ('_id' in request) {
Property.findById(id).then( async (property) => {
property.requests.push(request._id)
await property.save()
let response = {
status: 200,
message: lang.__('general.success.created','Request')
}
return Promise.resolve(response)
})
}
}
catch (err) {
let response = {
status: 400,
message: lang.__('general.error.fatalError')
}
return Promise.reject(response)
}
}
In http request function:
exports.create = async (req, res) => {
try {
let response = await Request.create(req.params.id, req.body)
console.log(response)
res.send(response)
}
catch (err) {
res.status(err.status).send(err)
}
}
I tried returning Promise.resolve(response) and Promise.reject(response) with then and catch in the middleware function and is occurring the same.
What's wrong?
Thanks a lot, cheers
You don't necessarily need to interact with the promises at all inside an async function. Inside an async function, the regular throw syntax is the same as return Promise.reject() because an async function always returns a Promise. Another thing I noticed with your code is that you're rejecting promises inside a HTTP handler, which will definitely lead to unexpected behavior later on. You should instead handle all errors directly in the handler and act on them accordingly, instead of returning/throwing them.
Your code could be rewritten like so:
request.create = async (id, params) => {
let request = await new Request(Object.assign(params, { property : id })).save()
if ('_id' in request) {
let property = await Property.findById(id)
property.requests.push(request._id)
await property.save()
}
}
And your http handler:
exports.create = async (req, res) => {
try {
await Request.create(req.params.id, req.body)
res.send({
status: 200,
message: lang.__('general.success.created','Request')
})
} catch (err) {
switch (err.constructor) {
case DatabaseConnectionError: // Not connected to database
return res.sendStatus(500) // Internal server error
case UnauthorizedError:
return res.sendStatus(401) // Unauthorized
case default:
return res.status(400).send(err) // Generic error
}
}
}
Error classes:
class DatabaseConnectionError extends Error {}
class UnauthorizedError extends Error {}
Because you have that try/catch block inside your http handler method, anything that throws or rejects inside the Request.create method will be caught there. See https://repl.it/LtLo/3 for a more concise example of how errors thrown from async function or Promises doesn't need to be caught directly where they are first called from.

Categories