Before (trying) to switch to promises, I could have variables that were in the whole scope of the nested functions. For example, I could get a user
from a database, not use it right away, then use it in a function nested far along in the chain.
So, with promises, must I explicitly pass the needed variables into the next function? Or is there some other way to get around this?
Currently my code looks something like this
exports.add = function ( req, res ) {
var defer = q.defer()
// check sign in and get user information as 'user'
function getUser ( req, res ) {
User.findOne( { token: req.token }, function ( err, user ) {
if ( err || !user )
return res.json( {
status: "error",
message: "Error authenticating: " + err
})
return user
})
}
... // more functions here
defer.promise
.then( getUser )
.then( youtubeAuthenticate )
.then( getVideoId )
.then( youtubeFind )
.then( makeVideoObject )
defer.resolve( req, res )
}
The trouble is I can't access user
in functions like makeVideoObject
.
EDIT: Another thing that is really stumping me is how some of my functions can return a value, say videoId
and that seems to be recognized by my final function, makeVideoObject
, but others aren't, with no real difference between them. remain in scope, others become undefined
.
EDIT2: The reason my variable videoId
was "global" was because I guess I was declaring it like videoId = ...
. So it wasn't the return videoId
that made it global, but the way of declaring it. In that vain, I did this,
function getUserData () {
user = getUser()
videoId = getVideoId()
youtubeAuthenticate()
}
function getVideoData () {
vData = youtubeFind()
}
defer.promise
.then( getUserData )
.then( getVideoData )
.then( function (user, videoId, vData ) {
makeVideoObject( user, videoId, vData )
})
defer.resolve()
But no joy. Everything is still undefined
.
EDIT3: I've tried the responses below and any permutations I can think of. Here is what I have at the moment.
var user = getUser()
var videoId = getVideoId()
var video = q(videoId).then( youtubeFind )
q.all( [ user, video ] ).then( function( results ) {
if ( !results[0] )
return res.json( "Not authenticated." )
makeVideoObject( results[0], results[1] )
})
Using the debugger, both results are undefined. Using console.log
within the getUser()
and youtubeFind()
functions, I see they work. Here is the getUser()
function, for example.
function getUser () {
User.findOne( { token: req.token }, function ( err, user ) {
return user
})
}
Also note I've simplified things by adding the authenticateYoutube()
stuff right into youtubeFind()
.
Answer: I will probably choose an answer below out of courtesy, but this was a series of misunderstandings about Node and JS that made this problem. This doesn't answer the question as posed, but here's what I was doing wrong.
First, I thought that return
, when put in a nested function (closure) should be the return <VALUE>
for the "root" function it was nested in. Actually, it will only be the return value for the immediate function it's in. Probably JS 101 here. It also doesn't seem to be possible to affect variables declared in parent functions from within nested functions.
Second, you need to actually construct a function in a certain way for it to work like a promise. That format is like this:
function getUser () {
var defer = Q.defer() // create the promise object
User.findOne( { token: req.token }, function ( err, user ) {
defer.resolve( user ) // add the return value to the object
})
return defer.promise // return the object, with promise and value
}