【问题标题】:Returning a value from callback function in Node.js [duplicate]从Node.js中的回调函数返回一个值[重复]
【发布时间】:2014-06-13 22:18:54
【问题描述】:

我在从 Node.js 中的回调函数返回值时遇到了小麻烦,我会尽量简单地解释我的情况。考虑我有一个 sn-p,它获取 URL 并点击该 url 并给出输出:

urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) {                              
    var statusCode = response.statusCode;
    finalData = getResponseJson(statusCode, data.toString());
});

我试图将它包装在一个函数中并返回一个像这样的值:

function doCall(urlToCall) {
urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) {                              
    var statusCode = response.statusCode;
    finalData = getResponseJson(statusCode, data.toString());
    return finalData;
});
}

因为在我的 Node.js 代码中,我有很多 if-else 语句,其中 urlToCall 的值将被确定,如下所示:

if(//somecondition) {
   urlToCall = //Url1;
} else if(//someother condition) {
   urlToCall = //Url2;
} else {
   urlToCall = //Url3;
}

问题是urllib.request 中的所有语句都将保持不变,除了urlToCall 的值。所以我绝对需要把这些通用代码放在一个函数中。我尝试了同样的方法,但在doCall 中总是会返回我undefined。我试过这样:

response = doCall(urlToCall);
console.log(response) //Prints undefined

但是如果我在doCall() 中打印值,它会完美打印,但它总是会返回undefined。根据我的研究,我开始知道我们不能从回调函数返回值! (是真的)?如果是,任何人都可以建议我如何处理这种情况,因为我想防止每个 if-else 块中的重复代码。

【问题讨论】:

  • “是真的吗?” - 是的,当然。
  • @JanDvorak,所以除了复制代码我别无选择? ;)
  • 传递一些你自己的回调会有帮助吗?我相信是的。
  • 我认为这个链接可以帮助你理解它是如何工作的:github.com/maxogden/art-of-node#callbacks
  • @RodrigoMedeiros 感谢您提供出色的资源。我正在经历它,它帮助了我很多:)

标签: javascript node.js


【解决方案1】:

它的undefined 因为console.log(response)doCall(urlToCall); 完成之前运行。您还必须传入一个回调函数,该函数会在您的 request 完成时运行。

首先,您的功能。给它一个回调:

function doCall(urlToCall, callback) {
    urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) {                              
        var statusCode = response.statusCode;
        finalData = getResponseJson(statusCode, data.toString());
        return callback(finalData);
    });
}

现在:

var urlToCall = "http://myUrlToCall";
doCall(urlToCall, function(response){
    // Here you have access to your variable
    console.log(response);
})

@Rodrigo,在 cmets 中发布了 good resource。了解节点中的 回调 以及它们是如何工作的。请记住,它是异步代码。

【讨论】:

  • 这很好用。但我有一个问题。在里面调用 doCall 函数。如何返回响应变量?例如,如果我想在函数之外获取该变量?
  • @Romeo 同样的问题在这里!!
  • 这篇文章很有帮助,谢谢!
  • 嗨,如果我理解错了,很抱歉,但这有什么不同? urllib 响应现在只是停留在它之外的另一个函数的范围内。它不像你现在可以在 doCall 之外的任何地方使用响应对象?
  • 非常有帮助。总是避免创建回调,但我现在明白了。谢谢
【解决方案2】:

我在从 Node.js 中的回调函数返回值时遇到了小麻烦

这不是“小麻烦”,实际上不可能从一个异步函数中“返回”一个传统意义上的值。

由于您无法“返回值”,因此您必须在获得该值后调用需要该值的函数。 @display_name 已经回答了您的问题,但我只是想指出 doCall 中的返回是不以传统方式返回值。你可以这样写 doCall:

function doCall(urlToCall, callback) {
    urllib.request(urlToCall, { wd: 'nodejs' }, function (err, data, response) {                              
        var statusCode = response.statusCode;
        finalData = getResponseJson(statusCode, data.toString());
        // call the function that needs the value
        callback(finalData);
        // we are done
        return;
    });
}

callback(finalData); 行调用需要从异步函数获得的值的函数。但要注意,return 语句是用来表示函数到此结束,但并不表示将值返回给调用者(调用者已经移.)

【讨论】:

    【解决方案3】:

    node.js 的示例代码 - 异步函数到同步函数:

    var deasync = require('deasync');
    
    function syncFunc()
    {
        var ret = null;
        asyncFunc(function(err, result){
            ret = {err : err, result : result}
        });
    
        while((ret == null))
        {
             deasync.runLoopOnce();
        }
    
        return (ret.err || ret.result);
    }
    

    【讨论】:

    【解决方案4】:

    如果您想要让您的代码在不进行太多修改的情况下正常工作。您可以试试这个摆脱回调保持相同的代码工作流程的解决方案:

    鉴于您使用的是 Node.js,您可以使用 coco-request 来实现相同的目标,而无需担心回调。

    基本上,你可以这样做:

    function doCall(urlToCall) {
      return co(function *(){
        var response = yield urllib.request(urlToCall, { wd: 'nodejs' }); // This is co-request.                             
        var statusCode = response.statusCode;
        finalData = getResponseJson(statusCode, data.toString());
        return finalData;
      });
    }
    

    那么,

    var response = yield doCall(urlToCall); // "yield" garuantees the callback finished.
    console.log(response) // The response will not be undefined anymore.
    

    通过这样做,我们等待回调函数完成,然后从中获取值。不知何故,它解决了你的问题。

    【讨论】:

    • 但这是 ecma6 soultion
    • 它也会影响我的表现
    • ecma6 有问题吗?
    • 不,这不是问题,但问题是我们中的许多人仍然没有在他们的项目中使用 ECMA6,因为 node.js 在 ECMA 兼容性方面存在一些问题。
    猜你喜欢
    • 2016-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-15
    • 2019-11-05
    • 1970-01-01
    相关资源
    最近更新 更多