0

Really sorry if this has been asked a hundred times, but I haven't been able to adapt any previous SO solutions I found to my problem. A lot of them were Ajax specific.

I'm new to asynchronous callbacks with Node, and as such I'm having an issue with properly 'returning' data from an asynchronous callback. In my example, I'm trying to return CharList. The SQL queries and the data are all valid, so those aren't too important.

I've tried simply returning the values, which I quickly learned is impossible and defeats the purpose of asynchronous callbacks.

EDIT: I've also tried defining CharList outside of the function and then assigning the values through the function, but logging CharList after the function has finished prints an empty array.

// index.js
const sql = require('./sql')
const query = require('./queries');

function AllCharsToArray() {
    query.character.GetAllChars(function(result) {
        let CharList = [];
        for (var i in result) {
            CharList.push(result[i]._Name)
        }
    })
}

/*
{
    "characters":
    [
        {"_Name":"Charname 1"},
        {"_Name":"Charname 2"},
        {"_Name":"Charname 3"}
    ]
}
*/
// queries.js
const mysql = require('mysql');
const sql = require('./sql')

function GetAllChars(callback) {
    sql.conn.query(`SELECT _Name FROM characters;`, function(error, results, fields) {
        return callback(results); // returns RowDataPacket
    })
}

exports.character = {
    GetAllChars: GetAllChars,
}

Ultimately, I'm trying to get CharList to be available outside of AllCharsToArray so I can export them to an express.js route.

iced
  • 317
  • 3
  • 12
  • The previous solutions are not ajax specific, they're asynchronous-specific. See the question yours is marked a duplicate of. It has all the detail you need. You will need to communicate back the result from an asynchronous operation with either a callback or a promise. Pick one or the other. Your function returns BEFORE your non-blocking, asynchronous operation completes. Returning from within the callback just returns back into the database callback function - the containing function has already long since returned nothing. Remember, `return` applies to the immediate function scope only. – jfriend00 Jul 25 '19 at 02:53

2 Answers2

0

Suggested callback function contains error message, like

// queries.js
const mysql = require('mysql');
const sql = require('./sql')

function GetAllChars(callback) {
    sql.conn.query(`SELECT _Name FROM characters;`, function(error, results, fields) {
        // change as
        if(error) {
            return callback(error)
        }
        callback(null,results); // returns RowDataPacket
    })
}

exports.character = {
    GetAllChars: GetAllChars,
}

On index.js

...
function(req,res){
    query.character.GetAllChars(function(err,data){
       // check error info
       if(err){
          // console.debug(err)
          return res.send(err.message)
       }
       res.json(data)
    })
}
...

Xiaoyiyu
  • 19
  • 3
  • This is one way to do it. See the answer this question is marked a duplicate of for a lot more explanation and other options (like promises). – jfriend00 Jul 25 '19 at 02:55
  • @Xiaoyiyu Can you add some explanations of how your code works. What has to be fixed/changed from the submitter's code? – Léa Gris Jul 25 '19 at 02:56
  • This will call GetAllChars on every client request. – Rex Hsu Jul 25 '19 at 03:00
  • @LéaGris In the code, return the definition of the callback function with the currently defined error message, in order to determine whether it is an error in the final call, causing the callback function call to fail – Xiaoyiyu Jul 25 '19 at 03:02
  • @RexHsu This is a simple example that can be placed anywhere, sorry, the code description is too simple. – Xiaoyiyu Jul 25 '19 at 03:04
-1

Placing the CharList outside the AllCharsToArray()

// index.js
const sql = require('./sql')
const query = require('./queries');

query.character.GetAllChars(function(result) {
    const CharList = [];

    for (var i in result) {
        CharList.push(result[i]._Name);
    }
    // launch the route after GetAllChars is done
    expressApp.get('getCharList', (req, res) => {
        res.json(CharList);
    });
});
Rex Hsu
  • 464
  • 2
  • 7
  • I tried this, but attempting to log the `CharList` after the function has finished leads me to an empty array, just as it was defined. – iced Jul 25 '19 at 02:29
  • If you want to use callback way, check my edited post. Or you can study async / await way. – Rex Hsu Jul 25 '19 at 02:38