done() vs return done() - javascript

I was reading the docs for passport and I noticed that with serialize() and deserialize() done() is called with out being returned.
However when setting up a new strategy using passport.use() in the callback function return done() is used.
Is this something that needs to be understood or just copied from the docs?
http://www.passportjs.org/docs/
From the docs:
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));

return done() will cause the function to stop executing immediately. This means that any other lines of code after that line inside the function will be ignored and not evaluated.
done() not preceded by return, however, will not cause the function to stop executing. This means that any other lines of code after that line inside the function will be evaluated.
If you take a look at this passport.use() example (from the Passport docs), you'll see there is reachable code after the first three return done() statements, and you would want the function to exit immediately as soon as done() is called the first time to make sure none of the following instructions are evaluated:
passport.use(new BasicStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.validPassword(password)) { return done(null, false); }
// The following line is the success case. We do not want to execute it
// if there was an error, a falsy user or a user without a valid
// password. If we removed the return keywords from the previous lines
// of code, the success case would be triggered every time this
// function was called
return done(null, user);
});
}
));
Here I've added two executable snippets to illustrate the difference between done() and `return done(). The snippets are otherwise identical.
done() without return:
const done = console.log
const assessThreatLevel = threatLevel => {
if (threatLevel === 'all good') done('relax :)')
done('launch the missiles!')
}
assessThreatLevel('all good')
`return done():
const done = console.log
const assessThreatLevel = threatLevel => {
if (threatLevel === 'all good') return done('relax :)')
done('launch the missiles!')
}
assessThreatLevel('all good')
As an aside, I have taken to using return done() in most situations for consistency. As far as I'm aware, there's no drawback to using it. It can help you avoid bugs, and the return statement serves as a guarantee and a good visual reminder that the function will exit immediately after that statement is evaluated.

Related

avoid multiple returns looped in javascript - async / await to solve callback pyramid or callback hell,

I have this code, with a lot of blocks of returns, by example SignUp()
connectors.js
const connectors = {
Auth: {
signUp(args) {
return new Promise((resolve, reject) => {
// Validate the data
if (!args.email) {
return reject({
code: 'email.empty',
message: 'Email is empty.'
});
} else if (!isEmail(args.email)) {
return reject({
code: 'email.invalid',
message: 'You have to provide a valid email.'
});
}
if (!args.password) {
return reject({
code: 'password.empty',
message: 'You have to provide a password.'
});
}
return encryptPassword(args.password, (err, hash) => {
if (err) {
return reject(new Error('The password could not be hashed.'));
}
return User.create(Object.assign(args, { password: hash }))
.then((user) => {
resolve(createToken({ id: user._id, email: user.email }));
})
.catch((err2) => {
if (err2.code === 11000) {
return reject({
code: 'user.exists',
message: 'There is already a user with this email.'
});
}
return reject(err2);
});
});
});
},
};
module.exports = connectors;
then anoter code that call this code:
const connectors = require('./connectors');
CallsignUp(root, args) {
const errors = [];
return connectors.Auth.signUp(args)
.then(token => ({
token,
errors
}))
.catch((err) => {
if (err.code && err.message) {
errors.push({
key: err.code,
value: err.message
});
return { token: null, errors };
}
throw new Error(err);
});
}
how it's possible to avoid this in ES6 or ES7 or ES2017?
there are:
return()
.then()
return()
.then
and just loop returns:
return()
return()
return()
comming from PHP this code looks crazy, because return functions that return functions, and it's not clear for me, how is the name in javascript this type of block return code? calling functions that returns again more code?
UPDATED:
Code is not mine, full source in
https://github.com/jferrettiboke/react-auth-app-example
I'd like to understand by example:
return encryptPassword(args.password, (err, hash) => {
if (err) {
return reject(new Error('The password could not be hashed.'));
}
return User.create(Object.assign(args, { password: hash }))
.then((user) => {
.catch((err2) => {
return reject(err2);
/src/utils/auth.js (here is encryptPassword)
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt-nodejs');
const config = require('../config');
exports.encryptPassword = (password, callback) => {
// Generate a salt then run callback
bcrypt.genSalt(10, (err, salt) => {
if (err) { return callback(err); }
// Hash (encrypt) our password using the salt
return bcrypt.hash(password, salt, null, (err2, hash) => {
if (err2) { return callback(err2); }
return callback(null, hash);
});
});
};
there are 3 returns calling functions and returning values and functions? OOP is never like this, how to use Async/Await suggest by #dashmud, i don't want to learn old things like callbacks
This code needs to be refactored in a number of ways. First, you really, really don't want to mix promises and plain async callbacks in the same logic flow. It makes a mess and wrecks a lot of the advantages of promises. Then, you have an anti-pattern going using promises inside of new Promise(). Then, you have more nesting that is required (you can chain instead).
Here's what I'd suggest:
function encryptPasswordPromise(pwd) {
return new Promise((resolve, reject) => {
encryptPassword(pwd, (err, hash) => {
err ? reject(new Error("The password could not be hashed.")) : resolve(hash);
});
});
}
const connectors = {
Auth: {
signUp(args) {
// Validate the data
let err;
if (!args.email) {
err = {code: 'email.empty', message: 'Email is empty.'};
} else if (!isEmail(args.email)) {
err = {code: 'email.invalid', message: 'You have to provide a valid email.'};
} else if (!args.password) {
err = {code: 'password.empty', message: 'You have to provide a password.'};
}
if (err) {
return Promise.reject(err);
} else {
return encryptPasswordPromise(args.password).then(hash => {
args.password = hash;
return User.create(args);
}).then((user) => {
return createToken({id: user._id, email: user.email});
}).catch(err2 => {
if (err2.code === 11000) {
throw new Error({code: 'user.exists', message: 'There is already a user with this email.'});
} else {
throw err2;
}
});
}
}
}
};
Summary of Changes:
Collect all errors initially and do return Promise.reject(err) in one place for all those initial errors.
Promisify encryptPassword() so you aren't mixing regular callbacks with promise logic flow and you can then properly return and propagate errors.
Removing wrapping of the whole code with return new Promise() since all your async operations are now promisified so you can just return promises directly. This really helps with proper error handling too.
Undo unneccessary nesting and just chain instead.
Remove Object.assign() as there did not appear to be a reason for it.
In your edit, you asked for an explanation of this code segment:
return encryptPassword(args.password, (err, hash) => {
if (err) {
return reject(new Error('The password could not be hashed.'));
}
return User.create(Object.assign(args, { password: hash }))
.then((user) => {
.catch((err2) => {
return reject(err2);
This code calls encryptPassword().
It returns the result of that which is probably undefined so all the return is doing is controlling program flow (exiting the containing function), but since there is no code after that return at the same level, that's unnecessary.
You pass a callback to encryptPassword(). That callback is asynchronous, meaning it is called some time later.
The callback gets two arguments: err and hash. In the node.js async calling convention, if the first argument is truthy (e.g. contains some truthy value), then it represents an error. If it is falsey (usually null), then there is no error and the second argument contains the result of the asynchronous operation.
If there was an error, the parent promise is rejected and the callback is exited. Again, there is no return value from reject so the return is just for exiting the callback at that point (so no other code in the callback runs).
Then, another asynchronous operation User.create() is called and it is passed the args object with a new password set in it.
User.create() returns a promise so its result is captured with a .then() method and a callback passed to that.
Some time later, when the asynchronous User.create() finishes, it will resolve its promise and that will cause the .then() callback to get called and the result will be passed to it. If there's an error in that operation, then the .then() callback will not be called, instead the .catch() callback will be called. In that .catch() callback, the parent promise is rejected. This is a promise anti-pattern (resolving a parent promise inside another promise) because it is very easy to make mistakes in proper error handling. My answer shows how to avoid that.
Extending #jfriend00's answer, here's an approach that uses the ES2017 async / await syntax to flatten the callback pyramid or callback hell, however you prefer to call it:
const encryptPasswordPromise = require('util').promisify(encryptPassword)
const connectors = {
Auth: {
async signUp (args) {
const { email, password } = args
// Validate the data
let err
if (!email) {
err = { code: 'email.empty', message: 'Email is empty.' }
} else if (!isEmail(email)) {
err = { code: 'email.invalid', message: 'You have to provide a valid email.' }
} else if (!password) {
err = { code: 'password.empty', message: 'You have to provide a password.' }
}
if (err) {
throw err
}
let hash
try {
hash = await encryptPasswordPromise(password)
} catch (err) {
throw new Error('The password could not be hashed.')
}
const { _id: id, email } = await User.create(Object.assign(args, { password: hash }))
try {
return createToken({ id, email })
} catch (err) {
if (err.code === 11000) {
throw { code: 'user.exists', message: 'There is already a user with this email.' }
} else {
throw err
}
}
}
}
}
module.exports = connectors
Rather than handwrite my own promisified promise-based encryptPassword(), I opted to use a node.js builtin transformation function for that called util.promisify().
Overall, there are still a few improvements that could be made like moving the validation of the signUp() arguments to a separate function, but none of that is related to flattening the "callback hell" anti-pattern that gave rise to promise-based control-flow and async/await syntax.
First things first. There are no loops in your code.
If you're coming from PHP, then I would guess Javascript's asynchronous execution model looks alien to you. I would suggest learning more about Javascript.
Learn the following in the following order:
Callbacks
Promises
Generators
Async/Await
Those are the different approaches on how to handle Javascript's asynchronous execution model starting from the most basic (callbacks) to the most modern approach, "async/await".
Async/await would be the most readable but it would be better if you understand how async/await came to be since they are easy to use the wrong way if you don't understand what you're doing.

Confused about promises. Do I need to return here?

So I've recently started to learn Promises (Bluebird) and now I'm trying to use them as much as possible, but I'm a bit confused if I need to return promises in this case.
Here I have a Passport LocalStrategy that I made:
passport.use(new LocalStrategy(function(username, password, done) {
users.get(username) // A
.then(function(user) {
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
bcrypt.compare(password, user.password).then(function(result) { // B
if (result) {
return done(null, user);
}
return done(null, false, { message: 'Incorrect password.' });
});
})
.catch(function(err) {
return done(err);
});
}));
users.get(username) on line A uses the pg-promise library to return a promise that will resolve into a user if one is found in the database and to false if the user was not found.
bcrypt.compare on line B uses bcrypt to check if the password and hash match. It returns a promise that will resolve to true or false.
The code works perfectly, I'm just confused if line A and B should return like so
return users.get(username) // A
return bcrypt.compare(password, user.password).then(function(result) { // B
The code works with and without returning the promises.
Is Passport/Node just waiting until it sees return done? Does this mean that this function is synchronous even though everything inside it is async? Normally you would return a promise and then use .then() on it but since LocalStrategy is not using .then() or .catch() I don't have to return anything? Any input is greatly appreciated. Thanks.
Passport does not support Promise that is why you must call done in a callback. You could return users.get(username)but the return value (promise) is never used. Do not forget that you can chain promises like the following :
users.get(username)
.then(function(user) {
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
return bcrypt.compare(password, user.password);
})
.then(function(result) { // B
if (result) {
return done(null, user);
}
return done(null, false, { message: 'Incorrect password.' });
})
.catch(function(err) {
return done(err);
});

bcrypt.compare cb is not a function error

I'm using passport-local and I've already hashed my passwords in my mongo database. I can't figure out why my bcrypt.compare() isn't working correctly. It says 'cb is not a function' but it is. I just saved the callback as a variable in the same file instead of saving it in my User schema. Anyone ran across this problem before or see any errors in my code??
passport.use(new LocalStrategy((username, password, done) => {
User.findOne({ username: username }).exec().then((user, err) => {
if (err) return done(err)
if (!user) return done(null, false, { message: 'Incorrect username.' })
const comparePassword = function (candidatePassword, hashedPassword, cb) {
bcrypt.compare(candidatePassword, hashedPassword, function (err, isMatch) {
if (err) return cb(err)
return cb(null, isMatch)
})
}
comparePassword(password, user.password, function (err, isMatch) {
if (err) return done(err)
if (!isMatch) return done(null, false, { message: 'Incorrect password.' })
return done(null, user)
})
})
}))
So after hours of struggling with bcrypt.compare, I just decided to clear out my database and create new users from scratch. I ended up using bcrypt.compareSync() and it finally verified my passwords! So make sure you have all of your methods defined on your model BEFORE you add users/whatever to your database. I thought I had already added the compare function but I guess I was wrong. Thanks for all of your help!
I also had the same error, just reinstall npm and bcrypt, be careful! see what version of node you are working that is also important. Regards
I encountered something like this before. It has to do with async handling and the fact that all your code is already in the .then() handler of a promise (user.findOne()). It's generally not a good idea to mix promises and the callback pattern.
What I ended up doing is wrapping my comparePassword function in a promise and then including it in the promise chain. My code was quite different, but in your case it would look something like this:
passport.use(new LocalStrategy((username, password, done) => {
function comparePassword(candidatePassword, hashedPassword) {
return new Promise((resolve, reject) => {
bcrypt.compare(candidatePassword, hashedPassword,
(err, isMatch) => {
if (err) return reject(err);
else if (!isMatch) reject(new Error('Incorrect Password'));
else resolve();
});
});
})
User.findOne({ username: username }).exec()
.then((user, err) => {
if (err) return done(err)
if (!user) return done(null, false, { message: 'Incorrect username.' })
return comparePassword(password, user.password)
})
.then(/*do stuff if password is a match*/)
.catch(/*do stuff iff not a match*/)
}))
You could also try to just
return comparePassword(password, user.password, function (err, isMatch) {
at the end of your .then(), and I'd declare comparePassword outside of the .then() like in my code above.
The code looks alright to me. Eventhough I didn't test it.
Does your password comparison has to be aSync? Have you considered using bcrypt.compareSync?
Example:
MyPasswordTool.prototype.validateHashedPassword = function(challlenger, hashedPassword) {
return bcrypt.compareSync(challlenger, hashedPassword);
};

Nodejs Q promise catch never called with passport js

I'm using the passport library for node to assist me in user signup. I'm also using the 'Q' promise library to avoid the pyramid of doom as I go through several asynchronous steps.
Everything works fine, until I throw an error from one of the promised steps. I would have assumed execution would drop into the .fail function, where I could handle the error and return out of passport with a failed signup. But for a reason that I don't understand, the .fail function never gets called. Instead, I just get a stackdump in my browser window and in my console.
The controlling code is here:
q.fcall(checkEmailIsFree({'email':email, 'username':username, 'password':password}))
.then(checkUsernameIsFree)
.then(registerUser)
.then(function (user) {
if (user) {
logDebug('REGISTERED: ' + email);
return done(null, user);
}
else {
logDebug('Could not register');
return done(null, false);
}
})
.fail(function (err) {
logError('I never get here');
return done(null, false);
})
.done();
And here's how I'm throwing, from within checkEmailIsFree
var error = new Error('Bad times. Email is in use: ' + email);
throw error;
Is there some overall express / node code somewhere that is set to fast dump out an exception somehow? Why isn't my catch being called? What am I missing?
I think done(onFulfilled, onRejected, onProgress) can help in this case. You can try:
q.fcall(checkEmailIsFree({'email':email, 'username':username, 'password':password}))
.then(checkUsernameIsFree)
.then(registerUser)
.then(function (user) {
if (user) {
logDebug('REGISTERED: ' + email);
return done(null, user);
}
else {
logDebug('Could not register');
return done(null, false);
}
})
.done(undefined, function (err) {
logError('Error!'); // used in case of reject
return done(null, false);
});

How to use Promise in Sequelize Js to return a Entity

var user = db.User.find({ where: { username: username }}).then(function(user) {
console.log("Authenticate"+user.authenticate(password));
if (!user) {
return null;
} else if (!user.authenticate(password)) {
return null;
} else {
return user;
}
}).catch(function(err){
return err;
});
I am Using Sequelize JS with Node JS.
I want the object of the user that matches the where clause.
but when I do return from then function . but it goes into infinite loop.
I am new to Node Js and I don't know how to use Promise in Node Js.
Please help mee
The return value from db.User.find() is a promise. It will never be a user, so your first line is incorrect.
What you'll need to do is call the next function in your processing chain from within the promise then callback. This is the standard practice in Node.
If you return something from a then promise callback it's assumed to be another promise, which allows you to chain multiple promises in a row (example). That's not what you're looking for.
Your example would be better as something like:
function authentication(err, user){
// Do something
}
db.User.find({ where: { username: username }}).then(function(user) {
console.log("Authenticate"+user.authenticate(password));
if (!user) {
authentication(null, null);
} else if (!user.authenticate(password)) {
authentication(null, null);
} else {
authentication(null, user);
}
}).catch(function(err){
authentication(null, user);
});
Note the use of a callback to signify the result of your authentication test. Note also err as the first parameter to the callback, which is standard Node convention.
Try to use try and catch block
Here is an example:
authentication: async (req,res) => {
try {
let user = await User.findOne({
where: {username: req.body.username}
});
user = user.toJSON();
console.log(user);
if (!user) {
console.log('Not a user');
}
}
catch (e) {
console.log(e)
}
}

Categories

Resources