在继续之前等待mysql数据库查询完成

时间:2018-03-10 15:16:43

标签: javascript mysql node.js

我遇到了一个问题,我希望在继续之前等待异步数据库查询及其操作。

我当然可以将操作放在金字塔中,但从长远来看它不会很酷,因为我必须在某些时候重复代码。

这是我的例子(由于数据库查询的异步,当然不能正常工作):

var level = 5;
var difficulty = 30; //example
let randomDecider = Math.floor(Math.random()*(50+level)+1);
if (difficulty < randomDecider) {
  var type;
  var name;
  var heroid = "";
  dbconn.query("SELECT * FROM owned_heroes WHERE user = ? AND equipped = 1", [req.session.login], function(err, result, fields) {
    heroid = result[0].heroid;
  });
  if (randomDecider > 50) {
    type = "skill";
    var ownedSkills = [];
    var skillsKeys = Object.keys(Skill);
    dbconn.query("SELECT * FROM owned_skills WHERE user = ? AND heroid = ? AND equipped = 1", [req.session.login, heroid], function(err, result, fields) {
      for (var i = 0; i < result.length; i++) {
        ownedSkills.push(result[i].name);
      }
    });
    //Here later I also want to remove ownedSkills from skillsKeys.
    name = skillsKeys[Math.floor(Math.random()*skillsKeys.length)];
  }
  else {
    type = "item";
    var itemsKeys = Object.keys(Item);
    var ownedItems = [];
    dbconn.query("SELECT * FROM owned_items WHERE user = ? AND heroid = ? AND equipped = 1", [req.session.login, heroid], function(err, result, fields) {
      for (var i = 0; i < result.length; i++) {
        ownedItems.push(result[i].name);
      }
    });
    //Here later I also want to remove ownedItems from itemsKeys.
    name = itemsKeys[Math.floor(Math.random()*itemsKeys.length)];
  }
  //Some other code using the type and name variable.

基于此的人可以解释我如何将其转换为有效的方式,比如在查询完成之前等待操作,然后再继续。 我试过async / await,但我目前无法理解。

对代码的任何其他建议都非常受欢迎 感谢。

1 个答案:

答案 0 :(得分:0)

我在评论中已经解释过使用Promise s。我假设您正在为您的NodeJS程序使用mysql库。

首先,为了避免金字塔(或者我们通常称之为回调地狱),我们可以尝试将异步函数包装成Promise,如下所示:

function queryPromise(str, params) { 
  return new Promise((resolve, reject) => {
    dbconn.query(str, params, (err, result, fields) => {
      if (err) reject(err); 
      resolve(result);
    })
  })
}

然后,我只宣传了重要部分:

var level = 5;
var difficulty = 30; //example
let randomDecider = Math.floor(Math.random() * (50 + level) + 1);
if (difficulty < randomDecider) {
  var type;
  var name;
  var heroid = "";

  queryPromise("SELECT * FROM owned_heroes WHERE user = ? AND equipped = 1", [req.session.login]).then(result => {
    heroid = result[0].heroid;
    if (randomDecider > 50) {
      ........

您也可以将此功能用于其他查询。可是等等!这与把它放入金字塔不一样吗?好吧,或多或少相同,通常是这样做的方式,所以你的代码按照我们想要的方式执行。但是现在,我们可以将Promise的.then()链接到其他查询中,并避免更多地缩进代码,这会导致创建回调地狱。虽然,这不是我喜欢做的事情,因为当我们不小心它时,Promise链接也会带来地狱。

如果您使用的是Node 8或更高版本,则使用async await是最佳解决方案。考虑到async await也使用Promise,我们可以这样做:

var level = 5;
var difficulty = 30; //example
let randomDecider = Math.floor(Math.random() * (50 + level) + 1);
if (difficulty < randomDecider) {
  var type;
  var name;
  var heroid = "";

  let heroidQuery = await queryPromise("SELECT * FROM owned_heroes WHERE user = ? AND equipped = 1", [req.session.login]);
  heroid = heroidQuery[0].heroid;

  if (randomDecider > 50) {
      ........

现在看起来好多了,不是吗?正如关键字所示,await会让您的代码等待从查询中检索结果。只是不要忘记将整个代码包装到async function()块中,因为await函数之外不允许async

async function myfunc() {
  var level 5;
  ....

我建议你研究一下mysql2/promise甚至sequelize这样的库,当你对Promises感到满意时(甚至更好,与async-await一起使用),它会使用Promises

我希望这会有所帮助。祝你好运!