从 Node.js 中的回调函数返回一个值

IT技术 javascript node.js
2021-01-16 18:24:55

我在从 Node.js 中的回调函数返回一个值时遇到了一些小麻烦,我将尝试尽可能简单地解释我的情况。考虑我有一个片段,它获取 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;
}

问题是 a 中的所有语句urllib.request都将保持不变,除了 的值urlToCall所以我肯定需要把这些通用代码放在一个函数中。我也试过,但 indoCall总是会回报我undefined我试过这样:

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

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

4个回答

undefined原因是,console.log(response)doCall(urlToCall);完成之前运行您还必须传入一个回调函数,该函数在您的请求完成时运行

首先,你的功能。传递一个回调:

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,在评论中发布了一个很好的资源阅读节点中的回调及其工作原理。请记住,它是异步代码。

这工作正常。但我有一个问题。在里面调用 doCall 函数。我如何返回响应变量?例如,如果我想在函数之外获取该变量?
2021-03-19 18:24:55
这个帖子很有帮助,谢谢!
2021-03-21 18:24:55
嗨,对不起,如果我误解了,但这有什么不同?urllib 响应现在只是停留在它之外的另一个函数的范围内。它不像您现在可以在 doCall 之外的任何地方使用响应对象?
2021-03-30 18:24:55
很有帮助。总是有点避免创建回调,但我现在明白了。谢谢
2021-04-06 18:24:55
@Romeo 同样的问题在这里!
2021-04-10 18:24:55

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

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

由于您无法“返回值”,因此您必须在拥有该值后调用需要该值的函数。@display_name 已经回答了您的问题,但我只想指出 doCall 中的 return不是以传统方式返回值你可以写 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;
    });
}

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

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);
}
救了我!谢谢你。
2021-03-22 18:24:55
这就像一个魅力,非常感谢。你可以在这里查看文档npmjs.com/package/deasync
2021-04-09 18:24:55

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

鉴于您使用的是 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.

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

它也会影响我的表现
2021-03-14 18:24:55
不,这不是问题,但问题是我们中的许多人仍然没有在他们的项目中使用 ECMA6,因为 node.js 在 ECMA 兼容性方面存在一些问题。
2021-03-19 18:24:55
但这是 ecma6 灵魂
2021-03-20 18:24:55
ecma6 有问题吗?
2021-03-22 18:24:55