I'm having a problem trying to break out of a promise statement when an error occurs in a catch statement.
I'm not sure if I can throw an error inside a catch statement.
The problem: The catch function isn't doing anything when I throw an error.
Expected result: For the catch statement to display an alert and break the promise chain.
The code:
if (IsEmail(email)) {
$('body').loadingModal({
position: 'auto',
text: 'Signing you in, please wait...',
color: '#fff',
opacity: '0.9',
backgroundColor: 'rgb(0,0,0)',
animation: 'doubleBounce'
});
var delay = function(ms){ return new Promise(function(r) { setTimeout(r, ms) }) };
var time = 2000;
delay(time)
.then(function() { $('body').loadingModal('animation', 'foldingCube'); return delay(time); } )
.then(function() {
firebase.auth().signInWithEmailAndPassword(email, password)
.then(function () {
var user = firebase.auth().currentUser;
uid = user.uid;
configure();
})
.catch(function(error) {
throw error;
});
})
.then(function() { $('body').loadingModal('color', 'white').loadingModal('text', 'Welcome to Dtt deliveries').loadingModal('backgroundColor', 'orange'); return delay(time); } )
.then(function() { $('body').loadingModal('hide'); return delay(time); } )
.then(function() { $('body').loadingModal('destroy') ;} )
.catch(function(error) {
alert("Database error: " + error);
});
}
else {
alert("Please enter a valid email");
return;
}
The second .then after the delay resolves immediately, because nothing is being returned from it. Return the signInWithEmailAndPassword call instead, because it returns a Promise that you need to chain together with the outer Promise chain:
.then(function() {
return firebase.auth().signInWithEmailAndPassword(email, password)
// ...
Also, catching and immediately throwing doesn't really do anything - unless you need to handle an error particular to signInWithEmailAndPassword there, feel free to omit that catch entirely:
delay(time)
.then(function() { $('body').loadingModal('animation', 'foldingCube'); return delay(time); } )
.then(function() {
return firebase.auth().signInWithEmailAndPassword(email, password)
})
.then(function () {
var user = firebase.auth().currentUser;
uid = user.uid;
configure(); // if configure returns a Promise, return this call from the `.then`
})
.then(
// ...
.catch(function(error) {
alert("Database error: " + error);
});
If configure returns a Promise as well, then you need to return it too. (if it's synchronous, there's no need)
(you might also consider using a more user-friendly way of displaying the error, perhaps use a proper modal instead of alert)
Another option to consider is using await instead of all these .thens, the control flow may be clearer:
(async () => {
if (!IsEmail(email)) {
alert("Please enter a valid email");
return;
}
$('body').loadingModal({
position: 'auto',
text: 'Signing you in, please wait...',
color: '#fff',
opacity: '0.9',
backgroundColor: 'rgb(0,0,0)',
animation: 'doubleBounce'
});
var delay = function(ms) {
return new Promise(function(r) {
setTimeout(r, ms)
})
};
var time = 2000;
try {
await delay(time);
$('body').loadingModal('animation', 'foldingCube');
await delay(time);
await firebase.auth().signInWithEmailAndPassword(email, password)
var user = firebase.auth().currentUser;
uid = user.uid;
configure(); // if this returns a Promise, `await` it
$('body').loadingModal('color', 'white').loadingModal('text', 'Welcome to Dtt deliveries').loadingModal('backgroundColor', 'orange');
await delay(time);
$('body').loadingModal('hide');
await delay(time);
$('body').loadingModal('destroy');
} catch(error) {
alert("Database error: " + error);
}
})();
Related
I'm trying to make a helper function to get the current location of the user, but the result of my promise is undefined.
This function is working and I can retrieve my coordinates :
//position.js
async function getCurrentPosition() {
return new Promise((resolve, reject) => {
Geolocation.getCurrentPosition(resolve, reject, {
enableHighAccuracy: true,
timeout: 15000,
maximumAge: 10000,
});
});
}
export async function getUserLocation() {
await request(
// Check for permissions
Platform.select({
android: PERMISSIONS.ANDROID.ACCESS_COARSE_LOCATION,
ios: PERMISSIONS.IOS.LOCATION_WHEN_IN_USE,
}),
).then((res) => {
console.log('then');
// Permission OK
if (res === 'granted') {
console.log('granted');
return getCurrentPosition();
// Permission denied
} else {
console.log('Location is not enabled');
}
});
}
But when I call my function here, I get undefined :
import {getUserLocation} from '../../utils/position';
useEffect(() => {
getUserLocation()
.then((res) => console.log(res)) // { undefined }
.catch((err) => {
console.error(err.message);
});
}, []);
What am I doing wrong?
As written, getUserLocation() does not return its request(...).then() promise. Change await to return.
Also, you should really change console.log('Location is not enabled') to throw new Error('Location is not enabled'), thus allowing getUserLocation's caller to see the error (should it arise).
export async function getUserLocation() {
return request(Platform.select({ // Check for permissions
// ^^^^^^
'android': PERMISSIONS.ANDROID.ACCESS_COARSE_LOCATION,
'ios': PERMISSIONS.IOS.LOCATION_WHEN_IN_USE
}))
.then((res) => {
if (res === 'granted') { // Permission OK
return getCurrentPosition();
} else { // Permission denied
throw new Error('Location is not enabled'); // Throwing an Error here
// makes it available to the caller
// in its catch clause.
}
});
}
i was trying out promise code but it always returns me resolve even if the user does not exist in the database
can anyone help me fix my code and the return statement
in the return function the the second console log is only working.
here is my code
Api Call
const email = 't#t.com';
const request = require('request');
function IsUserExists(email, kc_accessToken) {
let url = `${path}/users?email=${email}`;
return new Promise(function (resolve, reject) {
request(
{
url: url,
headers: {
'content-type': 'application/json',
authorization: `Bearer ${kc_accessToken}`,
},
},
function (error, response, body) {
if (error) {
console.log('some error occured');
}
if (response.body.length > 0) {
console.log('User Exist');
return resolve();
}
console.log('Does not Exist');
return reject();
}
);
});
}
Function Call
http
.createServer(function Test() {
getAccessToken()
.then(function (response) {
kc_accessToken = response.data.access_token;
IsUserExists(email, kc_accessToken).then((resp) => {
if (resp) {
console.log('Do Not Create');
} else if (!resp) {
console.log('Creat a new User');
}
});
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
})
.listen(8081);
When Provided user email which exist ( t#t.com )
When Provided user email which does not exist( 09#t.com )
I need to create a new answer for example to you question in comments.
Now, you go into the reject function so you need to handle this rejection in the outside.
if (response.body.length > 0) {
console.log('User Exist');
return resolve();
}
console.log('Does not Exist');
return reject(); // -> Now here you are
You need add .catch function after IsUserExists.then().
It will be IsUserExists.then().catch()
http.createServer(function Test() {
getAccessToken()
.then(function (response) {
kc_accessToken = response.data.access_token;
// here you only accept the data from resolve in Promise
// so you need to add .catch function to handle the rejection.
IsUserExists(email, kc_accessToken).then((resp) => {
if (resp) {
console.log('Do Not Create');
} else if (!resp) {
console.log('Creat a new User');
}
}).catch((error) => {
console.log(error)
});
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
})
.listen(8081);
By the way, you could add parameter in rejection function like reject(new Error("user not found)).
Then in the outside, you can get this rejection message.
async await is very confusing. I have the below code and here I am trying to implement a create user function that first needs to check if the user exists in my MySQL database. I have the initial setting of the user where I call await on my findByUsername function. However, The function finishes after my if(!user) code has been executed.
I want the program to wait for the findByUsername function to finish and then perform the check on whether the user exists or not.
const { username, password, firstname, permission } = req.body;
let user = await User.findByName(req.body.username, (err, data) => {
if (err) {
if (err.kind === "not_found") {
console.log("finished");
return null;
} else {
console.error("error occurred");
}
} else {
console.log("finished too");
return data;
}
});
if (!user) {
console.log("couldnt find user");
res.status(404).send("couldnt find it :(");
} else {
console.log("found user");
res.send("found them");
}
===EDIT===
I am getting another that has also been confusing me where it says that result is not a function inside of my findByName function on my User model.
sql.query(`SELECT * from users WHERE username = '${username}'`, (err, res) => {
if (err) {
console.log("error ", err);
result(err, null);
return;
}
if (res.length) {
console.log("found user: ", res[0]);
result(null, res[0]);
return;
}
console.log("couldnt find");
return { kind: "not_found" }, null;
});
};
We must use await inside an async function.
For example:
const getUser = async (username) => await User.findByName(username);
Then call that function inside a try catch
try {
user = getUser(someUsername)
} catch (error) {
// Handle errors here
}
// Code here will only run once getUser is finished
Since i don't know your UserService i don't know if "User.FindByName" is a async function. but if that is the case you could do it like this:
const { username, password, firstname, permission } = req.body;
try {
let user = await User.findByName(req.body.username);
if (!user) {
console.log("couldnt find user");
res.status(404).send("couldnt find it :(");
} else {
console.log("found user");
res.send("found them");
}
} catch (e) {
res.status(400).send(e);
}
Are you able to change the definition of User.findByName?
Instead of using await and also passing in a callback, why not remove the callback and process it synchronously?
let user = await User.findByName(username);
// Handle response here
this will solve your Problem If you are using sequelize with mysql you can use where
condition in your code so you can use more conditions in it
const { username, password, firstname, permission } = req.body;
try {
let user = await User.findOne({
where: { username: req.body.username },
attributes: { exclude: ['password', 'signup_token'] }
});
if (!user) {
console.log("couldnt find user");
res.status(401).send("couldnt find user with username" +
(req.body.username));
} else {
console.log("User Found");
return res.status(200).send("User Found With Username" +
(req.body.username));
}
} catch (error){
console.log(error);
return res.status(500).send(error);
}
The function finishes after my if(!user) code has been executed.
That is because you are mixing async/await with callbacks which you should not.
// Here you are mixing async/await and callbacks
let user = await User.findByName(req.body.username, (err, data) => { /*....*/ });
// it is the same as
function findByNameCallback(err, data) { /*.....*/ }
let user = await User.findByName(req.body.username, findByNameCallback);
// -- So you either remove the callback from the equation
var user;
try {
user = await User.findByName(req.body.username);
} catch (err) {
// Handle error
}
// Work with the user object...
// ----
// Or remove the async/await stuff
User.findByName(req.body.username, findByNameCallback);
I'm using the following two pieces of code :
Store.addUser(newUserInfo).then(function(firstResult) {
Store.getUserList().then(function(result){
console.log('this side');
console.log(result);
io.sockets.emit('userAdded', {
userMapByUserId: result
});
}, function(error) {
console.log('List of users could not be retrieved');
console.log(error);
io.sockets.emit('userAdded', {
userMapByUserId: []
});
}
);
}, function(rejection) {
socket.emit('userNotAdded', {
userId: -1,
message: rejection.reason,
infoWithBadInput: rejection.infoWithBadInput
});
});
and in Store :
var addUser = function(newUserInfo) {
var validationResult = Common._validateUserInfo(newUserInfo);
if (validationResult.isOK) {
return keyValueExists('userName', newUserInfo.userName).then(function(userNameAlreadyExists) {
if (userNameAlreadyExists) {
validationResult = {
isOK: false,
reason: 'Username already exists',
infoWithBadInput: 'userName'
};
return Promise.reject(validationResult);
} else {
var newUserId = generateUserId();
//TODO: change it somehting more flexible. e.g. a predefined list of attributes to iterate over
var newUser = {
'userName': newUserInfo.userName,
'password': newUserInfo.password,
'userId': newUserId,
'lastModificationTime': Common.getCurrentFormanttedTime(),
'createdTime': Common.getCurrentFormanttedTime()
};
var user = new User(newUser);
user.save(function(err) {
if (err) {
console.log(err);
console.log('There is a problem saving the user info');
return Promise.reject('There is a problem saving the user info');
} else {
console.log('A new user added: ');
console.log(newUser);
//return getUserList();
return Promise.accept(newUser);
}
});
}
});
} else {
return Promise.reject(validationResult);
}
};
But in the first code , when I do Store.addUser(newUserInfo) it always runs the first function (resolve function) which shouldn't be the case if we do return Promise.reject() in addUser. Any idea on why this happens ?
You've got two return statements too few, two too much, and are overlooking a non-promisified function call.
Store.addUser(newUserInfo).then(function(firstResult) {
return Store.getUserList().then(function(result){
// ^^^^^^
…
This one is not really problematic, as you don't chain anything after the resulting promise, but it shouldn't be missed anyway.
…
return keyValueExists('userName', newUserInfo.userName).then(function(userNameAlreadyExists) {
if (userNameAlreadyExists) {
…
} else {
…
var user = new User(newUser);
user.save(function(err) { … });
// ^^^^
}
});
In this then-callback, you are not returning anything from your else branch. The promise is immediately fulfilled with undefined, and the ongoing save call is ignored - your promises don't know about it, so they can't await it. That's why Store.getUserList() that follows next in the chain doesn't see the changes; they're not yet stored.
It's also the reason why your Promise.reject inside that callback is ignored, and why Promise.accept never caused any problems.
You will need to create a new promise for the result of the save invocation here (so that you actually can return it):
…
var user = new User(newUser);
return new Promise(function(resolve, reject) {
user.save(function(err) {
if (err) {
console.log(err);
console.log('There is a problem saving the user info');
reject('There is a problem saving the user info');
} else {
console.log('A new user added: ');
console.log(newUser);
resolve(newUser);
}
});
}); // .then(getUserList);
I'm working on an app for which we're using promises. I'm attempting to figure out what the better pattern is.
Breaking up concerns between thenables and rejecting the promise if an error. Rejection is then handled in a catch block. Or is it better to throw a new type of error and handle in the catch block?
Account.findOneAsync({email: request.payload.email})
.then(function (user) {
if (user) {
return user.compareHash(request.payload.password);
} else {
// Account not found
return Bpromise.reject('AccountNotFound');
}
})
.then(function (validPassword) {
if (validPassword) {
return request.auth.jwt.user.sign();
} else {
// Invalid password
return Bpromise.reject('InvalidPassword');
}
})
.then(function (jwt) {
var response = reply.success();
return response.header('authorization', jwt);
})
.catch(function (e) {
if (e === 'AccountNotFound' || e === 'Invalid Password') {
return reply(Boom.unauthorized('Invalid username/password'));
} else {
// Perhaps log something like unhandled error
return reply(Boom.unauthorized('Invalid username/password'));
}
});
Or nesting promising as such. I feel here that this is just going down the same rabbit hole of "callback hell" though.
Account.findOneAsync({email: request.payload.email})
.then(function (user) {
if (user) {
user.compareHash(request.payload.password)
.then(function (valid) {
if (valid) {
request.server.plugins.jwt.sign()
.then(function (jwt) {
var response = reply.success();
return response.header('authorization', jwt);
});
} else {
// Invalid password
return reply(Boom.unauthorized('Invalid username/password'));
}
});
} else {
// Account not found
return reply(Boom.unauthorized('Invalid username/password'));
}
})
.catch(function (e) {
console.log(e);
});
I think you can get the best of both worlds by throwing and then catching your boom objects.
One thing you're missing in both approaches is that when you're already inside a then handler, the idiomatic thing to do is throw an error rather than creating and returning a rejected promise. You also don't need an else block after a return statement:
Account.findOneAsync({email: request.payload.email})
.then(function (user) {
if (user) {
return user.compareHash(request.payload.password);
}
// Account not found
throw Boom.unauthorized('Invalid username/password');
})
.then(function (validPassword) {
if (validPassword) {
return request.auth.jwt.user.sign();
}
// Invalid password
throw Boom.unauthorized('Invalid username/password');
})
.then(function (jwt) {
var response = reply.success();
return response.header('authorization', jwt);
})
.catch(function (e) {
if (e.isBoom) {
return reply(e);
}
// Perhaps log something like unhandled error
return reply(Boom.unauthorized('Invalid username/password'));
});