在我的node.js
Express应用程序中,我正在使用superagent中间件进行ajax调用。该调用使用Node-
mysql
中间件通过许多数据库查询来获取复杂数组中的数据库数据。
在粘贴代码之前,我试图用语言解释我要做什么,尽管代码足以说明它想要做什么,另外, 第一个回调 中的
所有异步操作都应该以同步方式完成。
说明:
在第一个查询的回调中,将执行一次for循环以多次运行第二个查询,并且在每个循环之后,仅在第二个查询的回调完成后才调用下一个循环。接下来的代码行也是如此。
码:
但是, 如果需要,您可以 跳过 for循环的内幕(在注释中标记),以使事情简短明了。
conn.query("SELECT * FROM `super_cats`",function(error, results, fields) {
if(error){console.log("erro while fetching products for homepage "+ error);}
for(var i in results) { // FIRST FOR LOOP INSIDE THE FIRST QUERY CALLBACK
/*Innards of for loop starts*/
var elem = new Object();
var supcat_id=results[i].id;
elem.super_id =supcat_id;
elem.cats=new Array();
var cat= '';
/*Innards of for loop ends*/
conn.query("SELECT * FROM `categories` WHERE `supcat_id`="+supcat_id,function(error_cats, results_cats, fields_cats) {
if (error_cats) {console.log("erro while fetching cats for menu " + error_cats);}
for(var j in results_cats) {
/*Innards of for loop starts*/
cat= new Object();
var cat_id=results_cats[j].id;
cat.cat_id=cat_id;
cat.cat_name=results_cats[j].cat_name;
cat.subcats=new Array();
/*Innards of for loop starts*/
conn.query("SELECT * FROM `subcategories` WHERE `category`="+cat_id,function(error_subcats, results_subcats, fields_subcats) {
if (error_subcats) {console.log("erro while fetching subcats for menu " + error_subcats);}
for(var k in results_subcats ){
/*Innards of for loop starts*/
var subcat=new Object();
var subcat_id=results_subcats[k].id;
subcat.subcat_id=subcat_id;
subcat.subcat_name=results_subcats[k].subcategory;
cat.subcats.push(subcat);
elem.cats.push(cat);
/*Innards of for loop starts*/
}// end of for loop for results_subcats
});
}// end of for loop for result_cats
});
super_cats.push(elem);
}// end of for supercat results
res.send(super_cats)
});
我尝试了异步中间件,但徒劳无功,因为我无法弄清楚在这种情况下要使用哪个功能。
简而言之,要求是:
1)第一个回调中的所有异步操作都应以同步方式完成。
2)仅在完成所有计算之后才应将响应发送到ajax调用,而不是在此之前发送给ajax调用(因为如果事物与现有代码中的事物是异步的,可能会发生,
不是吗? )
它可能只是语义,但重要的是要了解您 不能
以同步方式运行它。您必须异步运行它,并管理处理顺序才能获得所需的效果。我发现,从我想如何转换数据(功能编程)的角度考虑这些问题是有用的,而不是在更加同步的环境中编写命令性代码。
从代码可以看出,您最终想要一个super_cats
看起来像这样的数据结构:
[
{
super_id: 1,
cats: [
{
cat_id: 2,
cat_name: "Category",
subcats: [
{
subcat_id: 3,
subcat_name: "Subcategory"
},
...
]
},
...
]
},
...
]
首先,将其提取到具有单个回调的单个函数调用中。
function getCategoryTree(callback) {
}
现在,让我们从顶部开始。您要运行一个异步函数(SQL查询),并且要生成一个数组,每个结果只有一个条目。对我来说,这听起来像是一项map
手术。但是,因为我们希望(其中一个值cats
)以异步方式确定,我们需要使用异步映射,它的async
库提供。
现在让我们填写async.map
签名。我们要映射到我们results
的for
循环(这是我们循环的功能等效项),并且对于每个循环,我们都希望将结果转换为
某种东西 -执行该 某 事 的异步函数称为迭代器。最后,一旦我们拥有所有转换后的数组元素,我们就想调用赋予函数的回调。
function getCategoryTree(callback) {
conn.query("SELECT * FROM `super_cats`", function(error, results, fields) {
async.map(results, iterator, callback);
});
}
让我们创建一个用于获取顶级类别信息的新函数,并使用其名称代替iterator
占位符。
function getCategoryTree(callback) {
conn.query("SELECT * FROM `super_cats`", function(error, results, fields) {
async.map(results, getSuperCategory, callback);
});
}
function getSuperCategory(resultRow, callback) {
}
现在我们需要确定我们要为每个项目退还什么resultRow
。根据上面的图表,我们想要一个对象,该对象super_id
等于行的ID,并且cats
等于顶级类别中的所有类别。但是,由于cats
也是异步确定的,因此我们需要运行下一个查询并转换
这些 结果,然后才能继续。
与上次类似,我们希望cats
数组中的每个项目都是一个对象,该对象具有来自查询结果的一些信息,但是我们还想要一个subcats
数组,该数组又是异步确定的,因此我们将async.map
再次使用它。但是,这一次,我们将使用匿名函数进行回调,因为在将结果提供给更高级别的回调之前,我们想对结果做一些事情。
function getSuperCategory(resultItem, callback) {
var supcat_id = resultItem.id;
conn.query("SELECT * FROM `categories` WHERE supcat_id` = " + supcat_id, function(error, results, fields) {
async.map(results, getCategory, function(err, categories) {
callback(err, { super_id: supcat_id, cats: categories });
});
});
}
如您所见,一旦async.map
完成,就意味着我们在此超级类别下拥有所有类别。因此,我们可以调用callback
我们想要在数组中的对象。
至此,我们只需要实现即可getCategory
。它将看起来非常类似于getSuperCategory
,因为我们想要做基本上相同的事情-
对于每个结果,返回一个对象,该对象具有查询中的一些数据,但也具有异步组件。
function getCategory(resultItem, callback) {
var cat_id = resultItem.id;
var cat_name = resultItem.cat_name;
conn.query("SELECT * FROM `subcategories` WHERE `category` = " + cat_id, function(error, results, fields) {
async.map(results, getSubCategory, function(err, subcategories) {
callback(err, { cat_id: cat_id, cat_name: cat_name, subcats: subcategories });
});
});
}
现在,我们只需要实现即可getSubCategory
。
function getSubCategory(resultItem, callback) {
callback(null, {
subcat_id: resultItem.id,
subcat_name: resultItem.subcategory
});
}
糟糕!我们需要的数据getSubCategory
没有异步组件!事实证明,我们根本不需要最后一个async.map
。我们本可以使用常规的数组映射;让我们改变getCategory
并getSubCategory
以这种方式工作。
function getCategory(resultItem, callback) {
var cat_id = resultItem.id;
var cat_name = resultItem.cat_name;
conn.query("SELECT * FROM `subcategories` WHERE `category` = " + cat_id, function(error, results, fields) {
var subcategories = results.map(getSubCategory);
callback(error, { cat_id: cat_id, cat_name: cat_name, subcats: subcategories });
});
}
function getSubCategory(resultItem) {
return {
subcat_id: resultItem.id,
subcat_name: resultItem.subcategory
};
}
值得注意的是,我们原来的方法效果很好;如果有可能getSubCategory
具有异步组件,则可以将其保持原样。
就是这样!这是我编写此答案时编写的代码;请注意,我不得不伪造一下SQL,但我认为这个想法就存在了:
var async = require("async");
// fake out sql queries
queryNum = 0;
var conn = {
query: function(query, callback) {
queryNum++;
var results = [1, 2, 3, 4, 5].map(function(elem) {
return {
id: queryNum + "-" + elem,
cat_name: "catname-" + queryNum + "-" + elem,
subcategory: "subcategory-" + queryNum + "-" + elem
};
});
callback(null, results, null);
}
};
function getCategoryTree(callback) {
conn.query("SELECT * FROM `super_cats`", function(error, results, fields) {
async.map(results, getSuperCategory, callback);
});
}
function getSuperCategory(resultItem, callback) {
var supcat_id = resultItem.id;
conn.query("SELECT * FROM `categories` WHERE supcat_id` = " + supcat_id, function(error, results, fields) {
async.map(results, getCategory, function(err, categories) {
callback(err, { super_id: supcat_id, cats: categories });
});
});
}
function getCategory(resultItem, callback) {
var cat_id = resultItem.id;
var cat_name = resultItem.cat_name;
conn.query("SELECT * FROM `subcategories` WHERE `category` = " + cat_id, function(error, results, fields) {
var subcategories = results.map(getSubCategory);
callback(error, { cat_id: cat_id, cat_name: cat_name, subcats: subcategories });
});
}
function getSubCategory(resultItem) {
return {
subcat_id: resultItem.id,
subcat_name: resultItem.subcategory
};
}
getCategoryTree(function(err, result) {
console.log(JSON.stringify(result, null, " "));
});
这里存在一些效率低下的问题,但是为了简单起见,我已经将它们掩盖了。例如,您可以一次查询所有类别ID,然后一次查询所有类别,而不是一遍又一遍地运行第二个子查询,然后,一旦获得所有数据,就可以循环遍历每个子查询。同步排列以取出所需的零件。
另外,还有更好的方法将树结构存储在关系数据库中。特别是,请看一下修改后的预排序树遍历。
问题内容: 我很难弄清楚为什么while循环实际上不会循环。它运行一次并停止。 我正在尝试使其循环,以便用户能够多次转换单位。任何帮助都欢迎! 问题答案: 问题在于,当您呼叫时,它会占用该号码,但不会占用该号码之后的换行符。要解决此问题,只需在调用后放一行代码。 示例和完整说明: 假设您输入“ km”,按回车,“ 123”,按回车。从程序的角度来看,输入流为。 该代码获取值,并且使输入超出第一个。
问题内容: 我只是发现我认为PLSQL与Oracle中的SQL有点意外的行为。 如果我在SQLDeveloper上运行此查询,则会得到5个结果: 但是,如果我在SQLDeveloper中运行以下语句: 变量 w_counter 以值1(怪异)结束 但最奇怪的部分是,如果我将查询封装在子查询中…… 该 w_counter 变量完成与价值5 … 你对此有什么要说的? 我正在使用Oracle 9.2i
问题内容: 上面的语句返回3行。但是下面的语句仅返回2行。 我知道为什么会这样,但是有一种方法可以强制item_id 1返回两次? 我要退货的示例: id-> 1筹码€2.50 id-> 1筹码€2.50 id-> 2可口可乐€1.60 -------------------- 总计€6.60 问题答案: 您可以加入另一个表,例如 或者只是在您的应用程序中复制它们。 您实际上不需要做您所要的。
我试图用Java实现一个简单的客户机-服务器应用程序。 这是代码: 客户端.java 服务器.java 这是主要类: 代码的逻辑很简单:客户端和服务器都在等待< code>while(true)循环中的消息。 服务器的< code>listen方法中的< code>while循环执行得很好。但是,在< code>listenForMessages方法中,循环似乎只执行一次。我只看到一个“在循环”印
我正在使用mysql存储过程,我花了两个小时试图弄清楚为什么这个游标只运行一次。(我假设它只运行了一次,因为我运行这个存储过程后只看到一条记录——最后有一个命令,我从前面创建的临时表中选择了所有内容) 注意,我已经尝试过在游标中单独运行查询,它运行正常(返回了多条记录,这是应该的)。 我认为这一定与我从循环中插入数据有关(我希望在每个循环过程中向临时表中插入一行数据)。
我对python中双for循环的使用感到困惑,这是我的代码: 输出如下: 它只对外循环的第一个值执行内循环,为什么会发生这种情况?我怎样才能让它在第一个和第二个变量的所有组合上循环?