【问题标题】:Function returning undefined when callback is not used, on using callback, JS says function not defined不使用回调时返回未定义的函数,使用回调时,JS说函数未定义
【发布时间】:2018-04-18 20:45:33
【问题描述】:

考虑到在 SO 上已经提出了类似的问题,我已经回答了其中的大部分问题。

我正在制作一个需要查询数据库以获取数据的 RESTful 服务。我编写了正确查询数据库但始终返回未定义的代码。代码在这里:

function returnAll(){
    ModuleDBService.find({},function(err,data){
        if(err){
            console.log('Error occured while retrieving the documents!');
        }
        return data;
    });
}

我正在使用以下方式导出模块:

module.exports = {
    getAll:returnAll
};

在挖掘了很多之后,我发现我需要使用回调来获取数据。我浏览了许多示例并尝试将类似的技术应用于我的代码,修改后的代码如下所示:

function getAllFromDatabase(callback){
    ModuleDBService.find({},function(err,data){
        if(err){
            console.log('Error occured while retrieving the documents!');
        }
        callback(returnAll(data));
    });
}


function returnAll(data){ return data;}

然后以与上述类似的方式返回它。

但现在我收到 ModuleDAO.getAll 不是函数的错误(我正在使用 var ModuleDAO = require('path to the database service')。

我尝试了许多代码变体,浏览了 YouTube 上的几个视频,所有这些视频要么导致返回未定义,要么返回上述错误。如果有人可以修复代码并阐明整个回调的事情(或者可以提供可靠的文档来理解它),那将是一个很大的帮助。

谢谢。

编辑:在所有非常有用的答案之后,这里是一个摘要:

回调不能返回数据,请传递您希望程序使用数据调用的函数(回调函数)。就我而言,是我的路由器返回数据。

以下是更正后的代码:

function returnAll(callback) {
    ModuleDBService.find({}, function (err, data) {
        if (err) {
            console.log("Error while retrieving the document!")
            callback(null);
        }
        callback(data);
    });
}

我在路由器中使用此代码:

mainAPIRouter.post('/api/module', function (req, res) {
    try {
        moduleDAO.getAll(function(data){
            res.status(200);
            res.json(data);
        });
    } catch (error) {
        res.status(500);
        return res.send("Invalid request");
    }
});

感谢所有帮助过的人! :)

【问题讨论】:

  • 对我来说,这似乎是一个 X/Y,实际上只是另一个副本:stackoverflow.com/questions/14220321/…
  • @KevinBHi!我知道存在类似的问题,并且我已经解决了大部分问题,只是我无法弄清楚为什么类似的解决方案会导致我的案例中出现未定义和错误。
  • 什么是未定义的?
  • 例如,returnAll 不返回任何内容,原因在我链接的副本中有所说明。如果那是未定义的,那么是的,这绝对是一个骗局。
  • 它实际上是那个 bug @KevinB 的副本。

标签: javascript node.js callback


【解决方案1】:

你很接近。您不需要returnAll() 函数,您需要导出getAllFromDatabase 并将callback 传递给它:

function getAllFromDatabase(callback){
    ModuleDBService.find({},function(err,data){
        if(err) {
            console.log('Error occured while retrieving the documents!');
        }
        callback(data);
    });
}

module.exports = {
    getAllFromDatabase: getAllFromDatabase
};

那么,当你想使用它的时候,你需要一个回调函数

dataModule.getAllFromDatabase(callbackHandler);

function callbackHandler(dataFromDatabase) {
    // this function will be executed when ModuleDBService executes the callback
    console.log(dataFromDatabase);
}

一个小细节:如果err是Truthy,你不应该执行回调:

if(err) {
    console.log('Error occured while retrieving the documents!');
} else {
    callback(data);
}

【讨论】:

  • 好答案。一个建议是,如果您在尝试调用它之前检查以确保回调是一个函数,它可以帮助使代码更加健壮。 if(typeof callback==='function') callback(data);
【解决方案2】:

您想简单地调用callback(),并将您需要的数据作为参数。通过将另一个函数传递给回调,您使事情变得更加复杂。尝试类似:

function returnAll(callback) {
  ModuleDBService.find({}, function(err, data) {
    if (err) return callback(err)
    callback(null, data);
  });
}

returnAll(function(err, data)) {
// it's customary for callbacks to take an error as their first argument
  if (err) {
    console.log('Error occured while retrieving the documents!');
  } else {
    // use data here!!
  }
}

【讨论】:

  • 非常感谢。我会尝试。在我看来,我现在只需要返回 else 部分中的数据并将模块导出为 getAll,对吗?
  • @metamemelord 在处理异步函数时,您永远无法返回 数据。 returnAll() 函数正在调用您的回调。如果从回调中返回,则将数据返回给刚刚调用它的函数。您需要使用回调中的数据或将其传递给另一个函数。
  • 好的。非常感谢。然后我将调用我的路由器并将数据直接导出到 json 中。所有这一切都是因为有多层逻辑而发生的。非常感谢所有的帮助。
【解决方案3】:

如前所述,您可以使用回调。如果您愿意,也可以使用 Promise:

function returnAll(){
    return new Promise(function(resolve, reject) {
    ModuleDBService.find({},function(err,data){
        if(err){
            console.log('Error occured while retrieving the documents!');
                reject(err);
        }
          resolve(data);
    });
     });
}

然后你可以使用类似的东西来访问它:

returnAll()
  .then(data=> {console.log(data); })
  .catch(err=> { console.log(err); });

*编辑:既然你想使用回调,我想我也会在那里加上我的 0.02 美元。最简化的方法是只使用您通过ModuleDBService.find 传入的回调,而不使用临时函数。但是最好验证一下回调实际上是一个函数,如果不把它变成一个......让你的代码更容错。

function returnAll(cb){
    if(typeof cb!=='function') cb = function() {};
    ModuleDBService.find({},cb);
}

【讨论】:

  • 感谢您的帮助。我现在正在与回调作斗争。我肯定也会学习 Promise,但是在我学习回调之后。非常感谢!
  • @metamemelord 不用担心...我添加了一些代码来展示如何以更精简的方式进行回调。需要注意的一件事是,如果您有多个按顺序运行的回调函数,回调有时会使代码难以阅读。您最终可能会在回调中的回调中获得回调……通常称为“回调地狱”。这就是发明 Promise 的原因;只是需要注意的事情。
  • @metamemelord 不客气,编码愉快!也只是一个建议,但除了将其标记为解决方案之外,您可能还会考虑支持 raul.vila 的答案。 Upvote 给他额外的 10 个代表点。
  • 我对所有三个答案都投了赞成票。当我投票时,我观察到有人对这三个人都投了反对票。我不知道为什么会这样。
  • 啊,对不起,你很好,很难判断何时反对票取消了赞成票,或者是否没有投票。
猜你喜欢
  • 1970-01-01
  • 2021-08-11
  • 1970-01-01
  • 1970-01-01
  • 2015-07-02
  • 1970-01-01
  • 1970-01-01
  • 2012-02-23
  • 1970-01-01
相关资源
最近更新 更多