gpt4 book ai didi

node.js, express - 在循环中以同步方式一个接一个地执行 mysql 查询

转载 作者:搜寻专家 更新时间:2023-10-31 22:17:56 33 4
gpt4 key购买 nike

在我的 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)
});

我尝试使用 async 中间件但徒劳无功,因为我无法弄清楚在这种情况下使用哪个函数。

简而言之,要求是:

1)第一个回调里面的所有异步的事情都应该以同步的方式来完成。

2) 只有在所有计算完成后才将响应发送到 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 operation对我来说。但是,由于我们希望异步确定其中一个值 ( cats ),因此我们需要使用异步映射,即 the async library provides .

让我们填写 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完成了,这意味着我们拥有了这个父类(super class)下的所有类;因此,我们可以拨打我们的 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根本;我们可以使用常规数组映射;让我们改变 getCategorygetSubCategory那样工作。
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,然后一次查询所有类别,等等。然后,一旦您拥有所有数据,您可以遍历每个类别阵列同步拉出你需要的部分。

此外,还有更好的方法在关系数据库中存储树结构;特别是,看看修改前序树遍历。

关于node.js, express - 在循环中以同步方式一个接一个地执行 mysql 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27646035/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com