我在Node中工作并尝试从我的数据库加载下一个序列。我能够访问数据库,加载并返回我的函数中的序列,但我无法在函数外部访问它。
function getRunId() {
counters.findOne({_id: 'Run_ID'}, function(err, resp) {
if(err) {
console.log(err);
}
console.log('Seq: ' + resp.sequence); // Console Output = Seq: 1234
return resp.sequence;
});
};
var currentRunId = getRunId();
console.log('Run_ID: ' + currentRunId); // Console Output = CRID: undefined
我已经检查了几页与Stack Overflow相关的问题,这些问题与使用回调,async(节点模块),如何正确返回函数中的值等有关...但是没有一个让我感到惊讶更接近访问函数外的currentRunId。
在我的函数中使用Mongo查询会使这个问题变得更复杂吗?
答案 0 :(得分:2)
对于后来遇到这种情况的人start by reading this answer。
我已经处理了几次,所以我理解沮丧。您正尝试通过执行以下操作来混合同步和异步代码:
var currentRunId = getRunId();
console.log('Run_ID: ' + currentRunId);
麻烦的是,在调用getRunID()之后立即调用console.log('Run_ID:'+ currentRunId),将其分配给当前的RunID,并在console.log之后解析getRunID()('Run_ID:'+ currentRunId ),导致currentRunId变量未定义。
但是,你有一些选择来解决这个问题。选项一是返回回调,而是记录回调的结果。选项2是使用ES6承诺。要使用选项2,您需要节点版本7,并且需要在代码中使用“use strict”。
以下是围绕函数存根构建的3个示例,它们欺骗了findOne()的结果。 getRunIdA()是你的函数,getRunIdB和getRunIdC是你当前问题的两个示例解决方案。
'use strict'
// A function stub which represents a simplified version of findOne.
// Accepts callback and returns a callback with the results of data
function findOne (callback) {
var data = {
sequence: 6
}
return callback(null, data)
}
// This is a simplified version of your function, which reproduces the undefined result
function getRunIdA () {
findOne(function (err, resp) {
if (err) {
console.log(err)
}
console.log('Seq: ' + resp.sequence)
return resp.sequence
})
}
// This is your function with a callback
function getRunIdB (callback) {
findOne(function (err, resp) {
if (err) {
console.log(err)
}
console.log('Seq: ' + resp.sequence)
return callback(resp.sequence)
})
}
// This is your function with a promise
var getRunIdC = new Promise(function (resolve, reject) {
resolve(findOne(function (err, resp) {
if (err) {
console.log(err)
}
return resp.sequence
}))
})
// Invoke your funciton; get undefined
var currentRunID = getRunIdA()
console.log('Run_ID: ' + currentRunID) // Run_ID: undefined
// Invoke getRunIdB using callback, get 6
getRunIdB(function (id) {
console.log('Run_ID: ' + id) // Run_ID: 6
})
// Invoke getRunIdC with a promise; get 6
getRunIdC.then(function (currentRunID) {
console.log('Run_ID: ' + currentRunID) // Run_ID: 6
})
/*
results for all 3:
Seq: 6
Run_ID: undefined
Seq: 6
Run_ID: 6
Run_ID: 6
*/
尝试保存到您的计算机并运行:
node test.js
在我的函数中使用Mongo查询会使这个问题变得更复杂吗?
不,您只需要将查询结果传递给承诺或回调,以便您可以在其他地方使用结果。
我希望这有帮助!
编辑:OP在评论中添加了以下代码,我将尝试分解并解决。
不幸的是,使用getRunIdB导致回调未定义并且使用getRunIdC导致currentRunId未定义
var currentRunID = '';
var getRunId = new Promise(function (resolve, reject) { resolve(counters.findOne({_id: 'Run_ID'}, function (err, resp) {
if (err) {
console.log(err)
}
return resp.sequence;
}))
});
getRunId.then(function (res) {
console.log('Run_ID: ' + res.sequence) // Run_ID: 1234
currentRunID = res.sequence;
})
console.log(currentRunID); // currentRunID is not defined
查看an answer I gave to a similar question以获取有关JS并发模型的更多详细信息。简单地说,getRunID()函数正在执行异步代码。这意味着getRunID()不会插入到消息队列中,该消息队列确定javascript将执行的顺序,直到它的回调完成为止。因此,当您在.then()函数之外记录currentRunID时,结果是未定义的,因为currentRunID未定义。
我认为OP最终要做的是导出函数的结果,以便可以用这些结果完成某些事情,这需要在回调中完成,如下所示:
getRunId.then(function (res) {
// Do stuff with the run ID here.
})
答案 1 :(得分:1)
您只返回回调函数而不是实际函数。将代码更改为:
function getRunId() {
var result = counters.findOne({_id: 'Run_ID'}, function(err, resp) {
if(err) {
console.log(err);
}
console.log('Seq: ' + resp.sequence); // Console Output = Seq: 1234
return resp.sequence;
});
return result; //<-- return result of your function is here
};
var currentRunId = getRunId();
console.log('Run_ID: ' + currentRunId);