我试图用NodeJS编写代码,从外部API抓取数据,然后使用Mongoose在MongoDB中填充它们。在这之间,我将检查该特定对象是否已经存在于Mongo中。下面是我的代码。
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回调是并行的,因此不会按顺序调用它。我的最终结果将是这样的:
我需要的是某种技术或方法来处理这些回调,它们在一个接一个地html" target="_blank">执行,而不是在循环之后顺序执行。我可以肯定这是问题所在,因为我的其他REST
API都可以正常工作。
我研究了异步方法,promise,递归函数以及其他一些我无法理解如何解决此问题的方法。我真的希望有人能对此事有所启发。
如果我在问问题的方式上有任何错误,也可以随时纠正我。这是我在StackOverflow中发布的第一个问题。
这个问题被称为“回调地狱”。还有很多其他方法,例如使用Promise和Async库。
我对本机async
ES7所带来的一切感到更加兴奋,您实际上可以立即使用Transpiler库Babel来使用它。
但是到目前为止,我发现的最简单的方法是:取出长的回调函数并在外部定义它们。
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());
...
问题内容: 我有一个数组(称为),其中包含数百个天文学图像文件的名称。然后处理这些图像。我的代码有效,并且需要几秒钟来处理每个图像。但是,一次只能执行一张图像,因为我是通过循环运行阵列: 没有理由我必须先修改映像,因此可以利用计算机上的所有4个内核,每个内核都通过for循环在不同的映像上运行吗? 我已经阅读了有关该模块的信息,但是不确定如何在我的情况下实现它。我热衷于工作,因为最终我必须在10,0
问题内容: 我需要有关node.js异步特性的帮助。我有一个for循环,该循环从数据库收集数据。“结果”是一个数组,然后应将其返回到主函数。 如何确保循环完成后执行回调? 问题答案: 您可能要考虑使用帮助程序库,例如 异步 https://github.com/caolan/async 它有助于使代码更加一致。 就您而言,您可以查看forEach()方法 调用迭代器时,将使用列表中的项目以及完成时
<---JS StackTrace---> =====JS栈迹=================================================================== 安全上下文:0x10178C2CFB51 2:main[/run-N6KBYU8CQZCNEXKH0TBM/solution.JS:~30][PC=0x2859725AEC0](this=0x10178
问题内容: 我是JavaScript和node.js的新手。我想遍历目录并将所有文件统计信息(而不是其他目录)添加到数组中。如下所示,我的代码存在问题,因为回调可能在for循环完成后被调用,因此在回调方法中使用“ i”变量将不起作用。但是代码应如何显示,以便以下代码段起作用?它与闭包有关吗? 感谢帮助! 问题答案: 您需要使用闭包是正确的。您应该将循环的内容包装在一个自调用函数中,以保留每次迭代的
伙计们如何处理这样的代码和警告? 我已经尝试过许多,但它总是在单独的线程中运行,我需要暂停当前的线程。 请帮帮忙..
问题内容: 今天,有人陪我一起滥用Java 中的关键字。我编写了一个简单的循环来验证数组中是否存在某些内容。假设是一个length数组,这是我的代码: 现在有人告诉我这不是一个很好的编程,因为我在循环内使用了该语句,这将导致垃圾回收发生故障。因此,更好的代码将是: 问题是我无法正确解释为什么第一个for循环不是一个好习惯。有人可以给我一个解释吗? 问题答案: 现在有人告诉我这不是一个很好的编程,因