James Obrien
James Obrien

Reputation: 21

Using NodeJS and MySQL, await/async functions sometimes not waiting for query to finish

I have two async functions,

async function sqlPushSteamappid(appId){
    let tmp;
    let sql='INSERT INTO cleetusbot.tmp (appId) VALUES ('+appId+');';
    tmp = new Promise((res, rej) => {
        global.pool.query(sql, function (err, results, fields) {    
            if(err){
                console.log(err);
            }
        });
    });
    return await tmp;
}

and

async function sqlGetSteamNames(){
    let tmp;
    let sql='SELECT * FROM cleetusbot.steamGames INNER JOIN tmp ON cleetusbot.steamGames.appId = cleetusbot.tmp.appId;';
    tmp = new Promise((res, rej) => {
        global.pool.query(sql,function (err, results, fields) {    
            if(err){
                console.log(err);
            }
            res(results);
        });
    });
    await tmp;
    return tmp;
}

Both return what I need, however most of the time when they are called the MySQL queries either don't fully return completely, or don't return an answer at in within the promise. Am I missing something in my code or do I have to make the MySQL timeout longer? Here is how im calling them in my code:

for(let i = 0; i < gameList.length; i++){
                sqlPushSteamappid(gameList[i]);
            }
            //sometimes does not return anything
            let steamNameObj = await sqlGetSteamNames();

Upvotes: 0

Views: 194

Answers (1)

Edeph
Edeph

Reputation: 772

First of all you should understand why things happen the way they do in your snippet.

Don't think of your mysql at all, those asynchronous calls act like any other; also take into account that a for iteration is asynchronous itself which means that all the function calls inside for will be called without waiting for the previous to be finished (even if you await them). sqlGetSteamNames() will also be called right after all your sqlPushSteamappid() are called (again, without waiting for them to finish).

You need to get rid of the uncertainty of execution order and you can do that having your sqlPushSteamappid() return a promise, and use Promise.all (docs here) to coordinate your requests. So first feed all your sqlPushSteamappid() in Promise.all and then after it returns, you can call await sqlGetSteamNames() as you do in your code.

Working example:

const promises = [
    new Promise((resolve, reject) => {
        setTimeout(() => resolve("3 sec passed"), 3000);
    }),
    new Promise((resolve, reject) => {
        setTimeout(() => resolve("2 sec passed"), 2000);
    }),
    new Promise((resolve, reject) => {
        setTimeout(() => resolve("4 sec passed"), 4000);
    })
];

const ending = async () => { setTimeout(() => { console.log("2 sec to finish") }, 1000); }

const start = async () => {
    const results = await Promise.all(promises);
    console.log(results);
    await ending();
}

start();

Upvotes: 1

Related Questions