NodeJS回调范围问题

时间:2013-12-05 20:36:19

标签: javascript node.js express callback

我很新(刚刚开始本周)到Node.js,有一个基本的部分,我无法理解。我有一个辅助函数,它调用MySQL数据库来获取一些信息。然后我使用回调函数将数据返回给调用者,但是当我想在该回调之外使用该数据时,我遇到了麻烦。这是代码:

    /** Helper Function **/
    function getCompanyId(token, callback) {
            var query = db.query('SELECT * FROM companies WHERE token = ?', token, function(err, result) {
                var count = Object.keys(result).length;

                if(count == 0) {
                    return;
                } else {
                    callback(null, result[0].api_id);
                }
            });
        }

/*** Function which uses the data from the helper function ***/
    api.post('/alert', function(request, response) {
        var data = JSON.parse(request.body.data);
        var token = data.token;

        getCompanyId(token, function(err, result) {
            // this works
            console.log(result);
        });

        // the problem is that I need result here so that I can use it else where in this function.
    });

正如您所看到的,只要我保持在回调范围内,我就可以访问getCompanyId()的返回值,但我需要在回调之外使用该值。我能够在另一个函数中解决这个问题,只需将所有逻辑都放在回调中,但在这种情况下不起作用。任何关于如何更好地构建这一点的见解都将是最受欢迎的。到目前为止我真的非常喜欢Node.js,但显然我已经学习了很多

4 个答案:

答案 0 :(得分:5)

简短回答 - 如果不违反Node.js的异步特性,就不能这样做。

考虑在回调之外尝试访问result的后果 - 如果您需要使用该值,并且回调尚未运行,您会怎么做?您不能sleep并等待设置值 - 这与Node的单线程,事件驱动设计不兼容。在等待回调运行时,整个程序必须停止执行。

依赖于result的任何代码都应该在getCompanyId回调中:

api.post('/alert', function(request, response) {
    var data = JSON.parse(request.body.data);
    var token = data.token;

    getCompanyId(token, function(err, result) {
        //Any logic that depends on result has to be nested in here
    });
});

学习Node.js(和异步编程是一般的)最困难的部分之一是学习异步思考。一开始可能很难,但值得坚持。您可以尝试在程序上进行战斗和编码,但这将不可避免地导致无法维护,错综复杂的代码。

如果您不喜欢多个嵌套回调的想法,可以查看 promises ,它允许您将方法链接在一起而不是嵌套它们。 This articleQ的一个很好的介绍,是承诺的一种实现。

答案 1 :(得分:2)

如果您担心在回调函数中塞满所有内容,您可以随时命名该函数,将其移出,然后将该函数作为回调函数传递:

getCompanyId(token, doSomethingAfter); // Pass the function in

function doSomethingAfter(err, result) {
    // Code here
}

答案 2 :(得分:2)

当我开始将这些视为“火与忘记”的方法时,我的“啊哈”时刻到了。不要查找从方法返回的返回值,因为它们不会返回。调用代码应该继续,或者只是结束。是的,感觉很奇怪。

正如@joews所说,你必须根据回调中的值放置所有内容。

这通常需要您传递额外的参数。例如,如果您正在执行典型的HTTP请求/响应,请计划沿着回调链向每个步骤发送响应。最终回调将(希望)在响应中设置数据,或设置错误代码,然后将其发送回用户。

答案 3 :(得分:1)

如果你想避免回调气味,你需要使用Node的Event Emitter Class,如下所示:

在文件顶部需要事件模块 -

var emitter = require('events').EventEmitter();

然后在你的回调中:

api.post('/alert', function(request, response) {
    var data = JSON.parse(request.body.data);
    var token = data.token;

    getCompanyId(token, function(err, result) {
        // this works
        console.log(result);
        emitter.emit('company:id:returned', result);
    });

    // the problem is that I need result here so that I can use it else where in this function.
});

then after your function you can use the on method anywhere like so:

getCompanyId(token, function(err, result) {
        // this works
        console.log(result);
        emitter.emit('company:id:returned', result);
    });

    // the problem is that I need result here so that I can use it else where in this function.
    emitter.on('company:id:returned', function(results) {
       // do what you need with results
    });

请注意为您的活动设置好的命名空间约定,这样您就不会弄乱事件,也应该观察您附加的听众数量,这里有一个很好的参考链接:

http://www.sitepoint.com/nodejs-events-and-eventemitter/

相关问题