NodeJS回调范围问题

NodeJS Callback Scoping Issue

本文关键字:问题 范围 回调 NodeJS      更新时间:2024-03-21

我是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,但显然我有很多东西要学

简短的回答-如果不违反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(异步编程是通用的)最困难的部分之一是学习异步思考。一开始可能很困难,但值得坚持。您可以尝试按程序进行战斗和编码,但这将不可避免地导致无法维护、复杂的代码。

如果您不喜欢多个嵌套回调的想法,可以查看promise,它允许您将方法链接在一起,而不是嵌套它们。本文很好地介绍了promise的一个实现Q

如果你担心回调函数中的所有内容都被塞满了,你总是可以命名函数,将其移出,然后将函数作为回调传递:

getCompanyId(token, doSomethingAfter); // Pass the function in
function doSomethingAfter(err, result) {
    // Code here
}

我的"啊哈"时刻到来了,我开始把这些看作是"fire-and-forget"方法。不要寻找从方法返回的返回值,因为它们不会返回调用代码应该继续,或者结束。是的,感觉很奇怪。

正如@joews所说,您必须将取决于该值的所有内容放入回调中。

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

如果你想避免回调气味,你需要使用Node的事件发射器类,比如:

文件顶部需要事件模块-

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/