node.js,表达-以同步方式在循环内一次又一次执行mysql查询

node.js,表达-以同步方式在循环内一次又一次执行mysql查询,第1张

node.js,表达-以同步方式在循环内一次又一次执行mysql查询

它可能只是语义,但重要的是要了解您 不能
以同步方式运行它。您必须异步运行它,并管理处理顺序才能获得所需的效果。我发现,从我想如何转换数据(功能编程)的角度考虑这些问题是有用的,而不是在更加同步的环境中编写命令性代码。

从代码可以看出,您最终想要一个

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 queriesqueryNum = 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,然后一次查询所有类别,而不是一遍又一遍地运行第二个子查询,然后,一旦获得所有数据,就可以循环遍历每个子查询。同步排列以取出所需的零件。

另外,还有更好的方法将树结构存储在关系数据库中。特别是,请看一下修改后的预排序树遍历。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5564816.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存