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

伊斯蒂亚克·艾哈迈德(Istiaque Ahmed)

在我的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调用(因为如果事物与现有代码中的事物是异步的,可能会发生,不是吗?

米歇尔·提里(Michelle Tilley)

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

从代码可以看出,您最终想要一个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签名。我们想要映射到我们resultsfor循环上(这是循环的功能等效项),并且对于每个循环,我们都希望将结果转换为某种东西-执行该的异步函数称为迭代器。最后,一旦我们拥有所有转换后的数组元素,我们就想调用赋予函数的回调。

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我们本可以使用常规的数组映射;让我们改变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,然后一次查询所有类别,而不是一遍又一遍地运行第二个子查询,然后,一旦获得所有数据,就可以循环遍历每个子类别。同步排列以取出所需的零件。

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

一次又一次地调用异步函数,直到 Node JS 中的预期结果

为什么 npm install 命令在 node app 中一次又一次地重新运行?

为什么图像请求在React JS中一次又一次触发?

高效的jQuery / JS-避免一次又一次地复制粘贴相同的代码

對js對象執行循環然後使用map方法而不是一次又一次地調用組件

Node js中的一次密码

Node.Js mysql仅在第一次执行

在同一个MVC项目中的C#类和JS文件中使用相同的静态数据,而无需在运行时一次又一次地重建

for循环一次又一次只使用第一个查询值

每秒定期调用一次node.js函数

如何让 Node JS 中的函数只运行一次

函数一次又一次运行,没有任何循环

如何一次又一次地重复(递归)查询?

如何减少一次又一次的firebase数据库查询?

Node.js 它打印两次相同的结果,而不是一次

在 Node.js 的循环中移动到下一次迭代之前等待 Promise

Virtual Machine Manager希望一次又一次地禁止Wayland上的快捷方式

以编程方式一次又一次地关闭SwiftUI视图不起作用

随着鼠标一次又一次地输入相同的链接,执行次数增加

一次又一次初始化时,指针在内部循环中做什么?

我试图让 while 循环在完成后由用户一次又一次地重复

主义doctrine:schema:update命令一次又一次地产生相同的查询集

JS for循环循环一次

Kafka一次又一次读取一批消息

在node.js中一次读取一行文件?

在node.js中一次读取一个字符的文件?

Node.js-一次遍历一组URLS

通知被一次又一次地触发

git文件一次又一次被删除