在函数中调用函数时异步Javascript上下文中的最佳实践?

在函数中调用函数时异步Javascript上下文中的最佳实践?,javascript,node.js,asynchronous,Javascript,Node.js,Asynchronous,我试图调用两个函数,并将第一个函数的输出作为参数传递给第二个函数 职能1: module.exports.getAllStatisticsByUserId = function(id, callback){ User.findById(id, (err, user) =>{ if(err) throw err; if(user) callback(null, user.statistics); }); }

我试图调用两个函数,并将第一个函数的输出作为参数传递给第二个函数

职能1:

module.exports.getAllStatisticsByUserId = function(id, callback){
    User.findById(id, (err, user) =>{
        if(err)
        throw err;
        if(user)
        callback(null, user.statistics);

    });
}
职能2:

module.exports.getGameByStatisticsId = function(id, callback){

    Statistics.findById(id, (err, statistics) =>{
        if(err)
        throw err;
        if(statistics)
        callback(null, statistics.game);
    });
};
我试图通过将第一个方法的输出作为参数传递来执行第二个方法,但是javascript的异步特性把它搞砸了。我曾试图履行承诺,但毫无结果


有人能推荐一些好的javascript实践来处理在相互需要时异步调用函数吗?任何帮助都将不胜感激。

看起来您应该能够写:

getAllStatisticsByUserId("me", (err, stats) => {
  getGameByStatisticsId(stats.id, (err, game) => {
    console.log(game);
  });
});
下面是这些函数返回承诺时的情况

getAllStatisticsByUserId("me")
  .then(stats => getGameByStatisticsId(stats.id))
  .then(game => console.log(game))
更好的是,如果您能够使用支持
async/await
的Node版本,那么您可以编写

let stats = await getAllStatisticsByUserId("me");
let game = await getGameByStatisticsId(stats.id);
console.log(game);
这意味着略微重写原始函数(除非
User.findById
Statistics.findById
已经返回)


看起来你应该能够写:

getAllStatisticsByUserId("me", (err, stats) => {
  getGameByStatisticsId(stats.id, (err, game) => {
    console.log(game);
  });
});
下面是这些函数返回承诺时的情况

getAllStatisticsByUserId("me")
  .then(stats => getGameByStatisticsId(stats.id))
  .then(game => console.log(game))
更好的是,如果您能够使用支持
async/await
的Node版本,那么您可以编写

let stats = await getAllStatisticsByUserId("me");
let game = await getGameByStatisticsId(stats.id);
console.log(game);
这意味着略微重写原始函数(除非
User.findById
Statistics.findById
已经返回)

修复后,可以按如下顺序调用它们:

module.exports.getAllStatisticsByUserId = function(id, callback){
    User.findById(id, (err, user) =>{
        if(err) callback(err);
        if(user) callback(null, user.statistics);
    });
};

module.exports.getGameByStatisticsId = function(id, callback){
    Statistics.findById(id, (err, statistics) =>{
        if(err) callback(err);
        if(statistics) callback(null, statistics.game);
    });
};
someService.getAllStatisticsByUserId(id).then(statistics =>
  someService.getGameByStatisticsId(statistics.id)
).then(game => {
  // handle game
}).catch(err => {
  // handle error
});
然而,如前所述:

回调
函数未传递时,将返回一个查询实例,该实例提供了一个特殊的查询生成器界面。 查询具有
.then()
函数,因此可以用作承诺

因此,您可以像这样简单地重写调用:

module.exports.getAllStatisticsByUserId = function(id, callback){
    User.findById(id, (err, user) =>{
        if(err) callback(err);
        if(user) callback(null, user.statistics);
    });
};

module.exports.getGameByStatisticsId = function(id, callback){
    Statistics.findById(id, (err, statistics) =>{
        if(err) callback(err);
        if(statistics) callback(null, statistics.game);
    });
};
someService.getAllStatisticsByUserId(id).then(statistics =>
  someService.getGameByStatisticsId(statistics.id)
).then(game => {
  // handle game
}).catch(err => {
  // handle error
});
或者将其转换为
async/await
函数:

async function getGameByUserId(id) {
  try {
    const statistics = await someService.getAllStatisticsByUserId(id);
    const game = await someService.getGameByStatisticsId(statistics.id);

    // handle game
  } catch (error) {
    // handle error
  }
}
请注意,
async
函数总是返回一个
Promise
,因此您必须
等待它或用
链接它。然后()
以确保查询完成并解析返回的值(如果有)。

修复后,您可以按如下顺序调用它们:

module.exports.getAllStatisticsByUserId = function(id, callback){
    User.findById(id, (err, user) =>{
        if(err) callback(err);
        if(user) callback(null, user.statistics);
    });
};

module.exports.getGameByStatisticsId = function(id, callback){
    Statistics.findById(id, (err, statistics) =>{
        if(err) callback(err);
        if(statistics) callback(null, statistics.game);
    });
};
someService.getAllStatisticsByUserId(id).then(statistics =>
  someService.getGameByStatisticsId(statistics.id)
).then(game => {
  // handle game
}).catch(err => {
  // handle error
});
然而,如前所述:

回调
函数未传递时,将返回一个查询实例,该实例提供了一个特殊的查询生成器界面。 查询具有
.then()
函数,因此可以用作承诺

因此,您可以像这样简单地重写调用:

module.exports.getAllStatisticsByUserId = function(id, callback){
    User.findById(id, (err, user) =>{
        if(err) callback(err);
        if(user) callback(null, user.statistics);
    });
};

module.exports.getGameByStatisticsId = function(id, callback){
    Statistics.findById(id, (err, statistics) =>{
        if(err) callback(err);
        if(statistics) callback(null, statistics.game);
    });
};
someService.getAllStatisticsByUserId(id).then(statistics =>
  someService.getGameByStatisticsId(statistics.id)
).then(game => {
  // handle game
}).catch(err => {
  // handle error
});
或者将其转换为
async/await
函数:

async function getGameByUserId(id) {
  try {
    const statistics = await someService.getAllStatisticsByUserId(id);
    const game = await someService.getGameByStatisticsId(statistics.id);

    // handle game
  } catch (error) {
    // handle error
  }
}


请注意,
async
函数总是返回一个
Promise
,因此您必须
等待它或用
链接它。然后()。。。不幸的是,你自己也这么说了:我建议你使用承诺。本教程对我非常有帮助:而不是
throw err您需要
回调(err)谢谢你的文章和提示!第一个方法没有输出。它所做的只是启动一个请求。当检索到该请求时,它可以选择调用一个可以访问结果的回调函数。因此,您希望在结果上执行的代码最好在该回调中,或者从该回调中调用。最佳实践?使用承诺。不要在异步回调中使用
throw
。是的。。。不幸的是,你自己也这么说了:我建议你使用承诺。本教程对我非常有帮助:而不是
throw err您需要
回调(err)谢谢你的文章和提示!第一个方法没有输出。它所做的只是启动一个请求。当检索到该请求时,它可以选择调用一个可以访问结果的回调函数。因此,您希望在结果上执行的代码最好在该回调中,或者从该回调中调用。最佳实践?使用承诺。在异步回调中不要使用
throw
。根据(假设基于
findById()
的使用),只要省略回调参数,函数就会返回实现
的对象。然后()
,所以不需要包装它们。@PatrickRoberts我认为Dan包装它们是正确的,因为问题是关于回调风格的代码,而不是具体的Mongoose方法。@PatrickRoberts我们怎么知道
findById
意味着Mongoose?可能是,可能是一个自定义模型类。@PatrickRoberts可能是,但当我们对它们进行假设时,它对任何试图学习的人都没有帮助。据我们所知,询问者自己编写了
findById
方法。我当然知道。我只是想确保这里的答案尽可能笼统,以便人们了解如何在所有情况下解决问题。根据(假设基于
findById()
)的使用,只要省略回调参数,函数就会返回实现
的对象。然后()
,所以不需要包装它们。@PatrickRoberts我认为Dan包装它们是正确的,因为问题是关于回调风格的代码,而不是具体的Mongoose方法。@PatrickRoberts我们怎么知道
findById
意味着Mongoose?可能是,可能是一个自定义模型类。@PatrickRoberts可能是,但当我们对它们进行假设时,它对任何试图学习的人都没有帮助。据我们所知,询问者自己编写了
findById
方法。我当然知道。我只是想确保这里的答案尽可能笼统,这样人们就能学会如何在所有情况下解决问题。