我可以在节点中的q promises中创建全局变量吗?

时间:2015-01-29 21:25:42

标签: javascript node.js promise

在尝试切换到promises之前,我可以拥有嵌套函数的整个范围内的变量。例如,我可以从数据库中获取user,而不是立即使用它,然后在嵌套在链中的函数中使用它。

那么,使用promises,我是否必须将所需的变量显式传递给下一个函数?或者还有其他方法来解决这个问题吗?

目前我的代码看起来像这样

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 )
}

问题是我无法在user等功能中访问makeVideoObject


编辑:另一件让我感到困惑的事情是我的一些函数如何返回一个值,比如videoId,这似乎被我的最终函数makeVideoObject所识别,但其他函数不是' t,它们之间没有真正的区别。留在范围内,其他人成为undefined


EDIT2:我的变量videoId是“全局”的原因是因为我猜我宣称它是videoId = ...。因此,return videoId不是使它全球化,而是宣布它的方式。那是徒劳的,我这样做了,

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()

但没有快乐。一切仍然是undefined


EDIT3:我已经尝试过以下的回复以及我能想到的任何排列。这就是我现在所拥有的。

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] )
})

使用调试器,两个结果都是未定义的。在console.loggetUser()函数中使用youtubeFind(),我发现它们有效。例如,这是getUser()函数。

function getUser () {
    User.findOne( { token: req.token }, function ( err, user ) {
        return user
    })
}

另请注意,我已将authenticateYoutube()内容添加到youtubeFind()中,从而简化了操作。


回答:我可能会出于礼貌而选择以下答案,但这是对Node和JS产生这一问题的一系列误解。这并没有回答所提出的问题,但这就是我做错了。

首先,我认为return,当放入嵌套函数(闭包)时应该是嵌套在它的“根”函数的return <VALUE>。实际上,它只会是返回它所具有的即时功能的价值。可能是JS 101。似乎也不可能在嵌套函数中影响父函数中声明的变量。

其次,你需要以某种方式实际构建一个函数,使它像promise一样工作。那种格式是这样的:

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
}

2 个答案:

答案 0 :(得分:2)

如果要运行多个不依赖的任务,然后运行需要这些值的任务,可以执行以下操作:

Q.all([getUserData(), getVideoData()]).spread(function(user, video) {
   // user and video are available
   makeVideoObject(user, video)
});

all获取可以并行获取的承诺列表; spread将这些返回值拆分为单个参数,然后可以在回调中使用。那是你想要做的吗?

答案 1 :(得分:2)

正如本杰明·格伦鲍姆所说You're Missing the Point of Promises

Promise不仅仅是将回调串联在一起的实用程序。它们是未来价值的占位符。

因此,如果你想在步骤列表的中间位置保留一个结果,你只需要抓住它:

var user = getUser();

user.then(doSomethingWithUser);
user.then(doSomethingElseWithUser);

您还没有向我们展示您的功能实际上做了什么,所以我会尽最大努力向您展示如何收集您需要的部分然后重新组合它们。我不确定是用“q”,你指的是Q,还是指$q,还是完全是其他的东西,所以我假设有最少的便利方法:

// All variables declared with "var" below are promises

var user = getUser();
var videoId = user.then(getVideoId); // assumes getVideoId depends on user
var youTubeAuth = user.then(youTubeAuthenticate);

var videoData = q.all([youTubeAuth, videoId]).then(function (values) {
    return getVideoData(values[0], values[1]);
});

var videoObject = q.all([user, videoId, videoData]).then(function (values) {
    return makeVideoObject(values[0], values[1], values[2]);
});