简体   繁体   English

意图返回之前循环返回的NodeJS MySQL查询

[英]NodeJS MySQL query in loop returning before intented

I am trying to create a function that would generate 4 unique id (hexadecimal) to insert into my database. 我正在尝试创建一个函数,该函数将生成4个唯一的ID(十六进制)以插入到我的数据库中。 I put the query inside a do while loop to check for collision, if the code is already present, I regenerate the code, if not, I return the value. 我将查询放入do while循环中以检查冲突,如果代码已经存在,则重新生成代码,如果不存在,则返回值。

The problem is that the loop exits before intended. 问题是循环在预期的时候退出。 For example if the code 'a' is generated but already presented in the database, the code gets regenerated but the loop exits and a new query never gets made. 例如,如果生成了代码“ a”但已经在数据库中显示了该代码,则将重新生成该代码,但是循环将退出,并且永远不会进行新的查询。 The new code does not get returned - instead the first code that was generated is returned. 新代码不会返回-而是返回生成的第一个代码。

Here's my code: 这是我的代码:

const FIND_EXISITNG_COURT =
  "SELECT access_code,team1,team2 FROM courts WHERE access_code= ?";

function generateAccessCode() {

  var random = Math.floor(Math.random() * (+30 - +0)) + +0;
  var code = random.toString(16);

  var hasDupe = false;

  do {
      connection.query(FIND_EXISITNG_COURT, [code], (err, results) => {

          if (err) {
              throw err;
          } else if (results.length > 0) {
              random = Math.floor(Math.random() * (+30 - +0)) + +0;
              code = random.toString(16);

              hasDupe = true;
          } else {
              hasDupe = false;
          }
      });
  } while (hasDupe);

  return code;
}

I am new to NodeJS so I don't know if it's bad practice to do this. 我是NodeJS的新手,所以我不知道这样做是否不好。 Any help would be much appreciated! 任何帮助将非常感激!

In your code, Callback function of query will be run later when the data has been ready, so hasDupe will be false at first time and generated code will be return. 在您的代码中, query回调函数将在数据准备好后再运行,因此hasDupe首次为false并将返回生成的代码。

You can use Promise and async function to solve your problem 您可以使用Promiseasync功能来解决您的问题

const FIND_EXISITNG_COURT =
"SELECT access_code,team1,team2 FROM courts WHERE access_code= ?";

function selectByCode(code) {  
    return new Promise((resolve, reject) => {
        connection.query(FIND_EXISITNG_COURT, [code], (err, results) => {
        if (err) {
            reject(err);
        } else {
            resolve(results.length)
        }
    });
}

async function generateAccessCode() {

    var random = Math.floor(Math.random() * (+30 - +0)) + +0;
    var code = random.toString(16);

    var hasDupe = false;

    let count =0;
    try{
        do {

            count = await selectByCode(code);
            if (count > 0) {
                random = Math.floor(Math.random() * (+30 - +0)) + +0;
                code = random.toString(16);

                hasDupe = true;
            } else {
                hasDupe = false;
            }


        } while (hasDupe);

        return code;
    }
    catch(e){
        throw e;

    }
}

Your call to connection.query is asynchronous, meaning the callback you've defined does not run right away. 您对connection.query调用是异步的,这意味着您定义的回调不会立即运行。 Your code just registers that callback and then keeps on executing until the end of generateAccessCode . 您的代码只注册该回调,然后继续执行直到generateAccessCode结束。 The callback doesn't get called until much later (when the db returns something) so hasDupe gets set only long after the original function has already exited. 直到很久以后(当数据库返回某些信息时),回调才被调用,因此hasDupe仅在退出原始函数后很长时间hasDupe设置。

You basically have 3 options to handle this: callbacks, promises, or async/await (which is really just syntactic sugar on top of promises). 基本上,您有3个选项可以处理此问题:回调,promise或async / await(实际上只是在promises之上的语法糖)。

An example using async/await but trying to keep as close to your original structure as I can (run it more than once to see it working): 使用async / await的示例,但尝试尽可能地保持与原始结构的距离(多次运行以查看其工作原理):

 // this is a mock for the db call. This "database" already holds records with IDs 0, 2 and 3. // IRL you will need to wrap your db call in a function that returns a promise // if you want to do it this way const connectionQuery = function (code) { return new Promise((resolve) => { setTimeout(() => resolve(code === 1 ? [] : [true]), 1000); }); } async function generateAccessCode() { // simplified the code generation for this example let code = Math.floor(Math.random() * 4); // Code can be 0, 1, 2, or 3 let hasDupe = false; let results; do { results = await connectionQuery(code); // await here is the key if (results.length > 0) { console.log(`Code ${code} already exists in the database. Generating new code...`); code = Math.floor(Math.random() * 4); hasDupe = true; } else { hasDupe = false; } } while (hasDupe); return code; } generateAccessCode() .then((code) => { console.log(`Final result: ${code}`); }) .catch((err) => { console.log(err); }); 

Using callbacks instead: 改用回调:

 // this is a mock for the db call. This "database" already holds records with IDs 0, 2 and 3. const connectionQuery = function (code, callback) { setTimeout(() => { callback(null, code === 1 ? [] : [true]); }, 1000); } function generateAccessCode(callback) { // simplified the code generation for this example let code = Math.floor(Math.random() * 4); // Code can be 0, 1, 2, or 3 let hasDupe = false; let results; connectionQuery(code, (err, results) => { if (err) { return callback(err); } if (results.length) { console.log(`Code ${code} already exists in the DB`); return generateAccessCode(callback); } callback(null, code); }); } generateAccessCode((err, code) => { console.log(`Final result: ${code}`); }); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM