我试图用NodeJS编写一个代码,从中获取外部API中的数据,然后使用Mongoose在MongoDB中填充它们。在此期间,我将检查这个特殊情况是否已经存在于蒙戈。下面是我的密码。
router.route('/report') // the REST api address
.post(function(req, res) // calling a POST
{
console.log('calling report API');
var object = "report/" + reportID; // related to the API
var parameters = '&limit=100' // related to the API
var url = link + object + apiKey + parameters; // related to the API
var data = "";
https.get(url, function callback(response)
{
response.setEncoding("utf8");
response.on("data", function(chunk)
{
data += chunk.toString() + "";
});
response.on("end", function()
{
var jsonData = JSON.parse(data);
var array = jsonData['results']; // data is return in array of objects. accessing only a particular array
var length = array.length;
console.log(length);
for (var i = 0; i < length; i++)
{
var report = new Report(array.pop()); // Report is the schema model defined.
console.log('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^');
console.log(i);
console.log('*****************************');
console.log(report);
console.log('*****************************');
// console.log(report['id']);
/*report.save(function(err)
{
if(err)
res.send(err);
});*/
Report.find({id:report['id']}).count(function(err, count) // checks if the id of that specific data already exists in Mongo
{
console.log(count);
console.log('*****************************');
if (count == 0) // if the count = 0, meaning not exist, then only save
{
report.save(function(err)
{
console.log('saved');
if(err)
res.send(err);
});
}
});
};
res.json({
message: 'Grabbed Report'
});
});
response.on("error", console.error);
});
})我的问题是,由于NodeJS回调是并行的,所以不会按顺序调用。我的最终结果会是这样的:
我需要的是某种技术或方法来处理这些回调,这些回调是一个接一个地执行,而不是按照循环顺序执行。我很确定这就是问题所在,因为我的其他REST都在工作。
我已经研究过异步方法、承诺、递归函数以及其他一些我能真正理解如何解决这个问题的方法。我真希望有人能对这件事有所了解。
如果我问问题的方式有任何错误,也可以纠正我。这是我在StackOverflow上发布的第一个问题。
发布于 2015-03-30 14:48:00
这个问题被称为“回调地狱”。还有很多其他方法,比如使用承诺和异步库。
我对本机ES7将带来的更多的兴奋,您可以在今天开始使用它,并使用转换程序库巴贝尔。
但到目前为止,我发现的最简单的方法是:取出长回调函数并在外部定义它们。
router.route('/report') // the REST api address
.post(calling_a_POST)
function calling_a_POST(req, res) {
...
var data = "";
https.get(url, function callback(response) {
...
response.on("end", response_on_end_callback); // --> take out
response.on("error", console.error);
});
}
function response_on_end_callback() { // <-- define here
...
for (var i = 0; i < length; i++) {
var report = new Report(array.pop());
...
Report.find({ id: report['id'] })
.count(Report_find_count_callback); // --> take out
};
res.json({
message: 'Grabbed Report'
});
}
function Report_find_count_callback(err, count) { // <-- define here
...
if (count == 0) {
report.save(function(err) { // !! report is undefined here
console.log('saved');
if (err)
res.send(err); // !! res is undefined here
});
}
}请注意,您将无法访问以前的回调中的所有变量,因为您已经将它们从作用域中删除。
这可以通过一个类型的“依赖注入”包装器来解决,以传递所需的变量。
router.route('/report') // the REST api address
.post(calling_a_POST)
function calling_a_POST(req, res) {
...
var data = "";
https.get(url, function callback(response) {
...
response.on("end", function(err, data){ // take these arguments
response_on_end(err, data, res); // plus the needed variables
});
response.on("error", console.error);
});
}
function response_on_end(err, data, res) { // and pass them to function defined outside
...
for (var i = 0; i < length; i++) {
var report = new Report(array.pop());
...
Report.find({ id: report['id'] })
.count(function(err, count){
Report_find_count(err, count, report, res); // same here
});
};
res.json({ // res is now available
message: 'Grabbed Report'
});
}
function Report_find_count(err, count, report, res) { // same here
...
if (count == 0) {
report.save(function(err) { // report is now available
console.log('saved');
if (err)
res.send(err); // res is now available
});
}
}当我执行response_on_end函数时,我得到了
undefined:1 unexpected token u错误。我很确定这与这一行有关:var jsonData = JSON.parse(data)我的response_on_end如下所示:var jsonData = JSON.parse(data); // problem here
我意识到我犯了一个错误:
function calling_a_POST(req, res) {
...
var data = "";
https.get(url, function callback(response) {
...
//sponse.on("end", function(err, data){
response.on("end", function(err){ // data shouldn't be here
response_on_end(err, data, res);
});
response.on("error", console.error);
});
}另一个我可以忽略的问题,这个问题实际上可能不会在这里出现,但还是最好还是谈一谈。data变量,因为它是一个与对象不同的原始类型的字符串,所以它是“通过值传递的”。更多信息
最好将变量包装在对象中并传递对象,因为javascript中的对象总是“通过引用传递”。
function calling_a_POST(req, res) {
...
// var data = ""; //
var data_wrapper = {};
data_wrapper.data = {}; // wrap it in an object
https.get(url, function callback(response) {
...
response.on("data", function(chunk){
data_wrapper.data += chunk.toString() + ""; // use the dot notation to reference
});
response.on("end", function(err){
response_on_end(err, data_wrapper, res); // and pass that object
});
response.on("error", console.error);
});
}
function response_on_end_callback(err, data_wrapper, res) {
var data = data_wrapper.data; // later redefine the variable
...
for (var i = 0; i < length; i++) {
var report = new Report(array.pop());
...发布于 2015-03-30 11:43:58
您可以使用异步库来控制执行流。还有用于处理数组的迭代器。
https://stackoverflow.com/questions/29343116
复制相似问题