javascript - Promises basics. How to promisify async node code? -
i getting started promises , trying use them instead of callbacks avoid callback hell. async functions mix of functions mongodb, redis, bcrypt module, etc. able far:
var insert = q.denodify(db.collection(users).insert); var createcollection = q.denodify(db.createcollection); var sadd = q.denodify(redisclient.sadd); var sismember = q.denodify(redisclient.sismember); var gensalt = q.denodify(bcrypt.gensalt); var hash = q.denodify(bcrypt.hash); // sanity check // "name" parameter required if(!req.body.name || !isvalidname(req.body.name)) return next(get400invalidnameerror()); // sanity check // "key" optional // if 1 supplied, must valid // key hashed later if(req.body.key){ if(!isvalidkey(req.body.key)) return next(get400invalidkeyerror()); } // steps: // 1. // check redis cache see if "name" taken // if yes, return error. if no, continue // 2. // construct "user" object name = req.body.name // 3. // req.body.key provided? // if yes, generate salt , hash key. set user.key = hash // if not, continue // 4. // create collection in mongodb same name req.body.name // 5. // add req.body.name cache // 6. // send response user using res.json() / res.end() sismember(users,req.body.name) .then(createuserobj,errhandler) .then(gensalt(10),errhandler) .then(hash(req.body.key,salt)) .then(createcollection(req.body.name),errhandler) .then(sadd(users,req.body.name),errhandler) .then(insert(user),errhandler) .then(get200usercreated,errhandler)
what confuses me last part of these functions then()
-ed together. have few questions:
1. how can result of 1 async function made available another?
2. how can conditionally decide functions executed? example, want generate salt , hash when req.body.key
provided.
3. then()
sequence proper?
- how can result of 1 async function made available another?
when use promise can resolve or reject it.
var myprom = promise.resolve(1) // simplest promise way
here if chain then
argument equal 1.
myprom.then(function( val ){ console.log(val); // 1 return 33; }).then(function(passed){ console.log(passed) // 33 return 44; }).then(function(other){ console.log(other) // 44 if( other > 44 ){ return 'aaa'; } else { return 'bbb'; } }).then(function(res){ console.log(res) // bbb })
here important thing return
promise.
async. part :
// can instanciate new promise object var myprom = new promise(function(resolve , reject){ console.log('we start here'); settimeout(function(){ console.log('we continue here'); resolve( 'time out' ); } , 2000); }).then(function( val ){ console.log('and end here : ' + val); });
the second part then
invoked call of resolve
in first part.
wait until end, it's "magic" of promise.
the argument passed resolve become argument of next then
.
same our first example return
important
when :
sismember(users,req.body.name)
it same principle timeout.
var sismember = function(users , req.body.name){ var promisetoreturn = new promise(function(resolve,reject){ var result = ''; // <---do users , req.body.name // , if ok if(result){ resolve( result ) } else {// if not ok reject( result ) } }); return promisetoreturn; // <-- can chain }) .then(createuserobj,errhandler)
the next (after sismember) invoke createuserobj
result
argument.
become :
var sismember = function(users , req.body.name){ var promisetoreturn = new promise(function(resolve,reject){ var result = ''; // <---do users , req.body.name // , if ok if(result){ resolve( result ) } else {// if not ok reject( result ) } }); return promisetoreturn; // <-- can chain }) .then(function createuserobj( resultofsismember){ var createduser = {} //<--- want resultofsismember // , return handled next then. if(everythingisok){ return createduser; } else { return promise.reject( 'error during creation'); // handled next error handler or catch } } , errhandler ); //<--- provide here error handler sismember
- how can conditionally decide functions executed? example, want generate salt , hash when req.body.key provided.
different way that.
- is then() sequence proper?
no !
you can't call function do.
.then(gensalt(10),errhandler) // <-- invoking result not function // doing that: .then('adekj34llkdf' , errhandler)
if want add argument use bind
.then(gensalt.bind(null , 10), errhandler) // invoke gensalt in null context 10 first argument
but promise chain provide argument prev function don't have provide !
see example above
once resolved problem, add catch @ end handle error occur. part :
.then(get200usercreated,errhandler)//<--- errhandler prev
have error handler part :
.then(insert(user),errhandler)
if have error during insert(user)
handled next error handler or catch.
sismember(users,req.body.name) .then(createuserobj,errhandler)// <-- errhandler : sismember .then(gensalt(10),errhandler)// <-- errhandler : createuserobj .then(hash(req.body.key,salt))// <-- missing errhandler : gensalt .then(createcollection(req.body.name),errhandler)// <-- errhandler : hash .then(sadd(users,req.body.name),errhandler)// <-- errhandler createcollection .then(insert(user),errhandler)// <-- errhandler : .then(get200usercreated,errhandler)// <-- errhandler : insert .catch(errhandler)// <-- errhandler : get200usercreated
i've wrote error handler here, should take @ that.
Comments
Post a Comment