javascriptnode.jsasynchronousasync-awaitnode-mysql2

How do I get promises to work in the right order in a function?


I'm trying to make a system that generates a radom ID number for a user and then checks if it is already in the mysql database. If it is then it will generate a new ID and check that against the database. It will continue this until it generates a unique identifier and return it to outside the function. I'm pretty new to JavaScript, Node and Asynchronous functions so I don't really know what I'm doing.

I've tried using promises, but the function always just returns "undefined" and checkChatIdExists doesn't finish until afterwards.

generateId() simply returns a 19 digit string and con is a database connection made with MySQL2

function checkChatIdExists(id) {
    return new Promise((resolve, reject) => {
        con.query("SELECT id FROM messages WHERE id = " + id, (err, result)=>{
            if(err !== null) { console.log(err) };
            if(result.length == 0) {
                resolve(id);  //newly generated id is okay
            } else {
                reject("ID was not Unique");         //newly generated id was not okay
            }
        })
    })
}

async function generateChatId() {
    
    async function generateAndCheckIdValid() {
        let id = await generateId();
        console.log("ID generated - " + id);
        checkChatIdExists(id).then((validId) => {
            return validId;       
        }).catch((message) => {
            console.log(message);
            return generateAndCheckIdValid();            //if id does exist then run again
        })
    }

    let id = await generateAndCheckIdValid();
    return id;
}

Solution

  • async function generateAndCheckIdValid() {
      const id = await generateId();
      console.log("ID generated - " + id);
      checkChatIdExists(id)
        .then((validId) => {
          return validId;
        })
        .catch((message) => {
          console.log(message);
          return generateAndCheckIdValid(); //if id does exist then run again
        });
    }
    
    

    This async function has no return statement in it, so it's promise will implicitly resolve to undefined. There's a return statement in a .then callback but that won't do anything of note. I recommend that you don't mix async/await with .then and just stick to one style. Using async/await the code would be:

    async function generateAndCheckIdValid() {
      let id = await generateId();
      console.log("ID generated - " + id);
      try {
        const validId = await checkChatIdExists(id);
        return validId;
        // If you prefer, the above 2 lines can be shortened to:
        // return await checkChatIdExists(id);
      } catch (message) {
        console.log(message);
        return generateAndCheckIdValid()
      }
    }
    

    If you prefer using .then, you would write the code like this:

    function generateAndCheckIdValid() {
      return generateId() // <--- note the `return`
        .then(id => {
           console.log("ID generated - " + id);
           return checkChatIdExists(id);
        })
        // You don't need a .then which just re-returns the value. The promise
        //   is already resolving to that value
        // .then(validId => { return validId })
        .catch(message) => {
          console.log(message);
          return generateAndCheckIdValid();
        });
    }