0

Array.push works fine if I console.log inside the loop. However, the array is empty outside the loop. Any thoughts on why?

It was working fine before, I changed something and the array has been empty ever since even if I undo the changes.

this.router.post('/hello', async(req, res) =>{

            console.log("We are in");
            var connection = mysql.createConnection({
                host     : 'host12',
                user     : 'root12',
                password : 'password12',
                database : 'db12',

            });

            var count = req.body.count;
            console.log("the count:" +count);


            while(i<count) {

                connection.query('INSERT INTO x (DateM) VALUES ("2021-10-10")', function (error, result, field) {
                    if (error) {
                        console.log("Insert Error: " + error);
                    } else {
                        insertID = result.insertId;

                        connection.query("UPDATE table SET mitID =" +insertID "where ID=" + insertID, function (errors, results, fields) {
                            if (errors) {
                                console.log("Update Errors: " + errors);
                            } else {
                                console.log(results);
                                var cId = Q + insertID;
                                idList.push(cId);


                            }
                        });

                    }
                });
                i++;
            }
            console.log(idList);
            res.json(idList);
        });

Thanks!

  • See https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron – jarmod Aug 24 '21 at 21:32
  • Does this answer your question? [How to return the response from an asynchronous call](https://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) – Robin Zigmond Aug 24 '21 at 21:40

2 Answers2

0
 while(i<count) {

     connection.query('INSERT INTO x (DateM) VALUES ("2021-10-10", ...
}
console.log(idList);
res.json(idList);

The problem is that you defined callback for connection.query and manipulated idList there.

This part res.json(idList); actually runs before query is completed.

To fix it, you need to use await.

while(i < count) {
    let {error, result, field} = await connect.query(...query);
    ...copy callback function body here

    i+++
}
...
Chuck
  • 776
  • 5
  • 18
0

The connection query does an async call that returns after the query is done allowing the console.log outside of the loop to run eventually before the queries initialised by have returned to execute the function defined inside the query return. So idList will be empty and then when the queries return idList will be populated.

Best is to use an event based return that basically waits for the queries to finish and then execute the next query in a queue.

Here is the code for such an event object:

var Web = {};
/**
 * Event handler class to handle event driven calls in a queue
 * @class Api.Events
 * @for MD
*/
Web.Events = function() {
    var callerList = new Array();

    /**
     * The current key at in the queue
     * @property Api.Events.CurrentKey
     * @type String
     * @for Api.Events
     */
    this.CurrentKey = "";

    /**
     * Add wait function in the queue to wait for.
     * @method Api.Events.AddWait
     * @param {String} key The key to add to the queue
     * @param {Function} functionCall The function to call
     * @param {Array} params List of parameters to pass to the function
     * @returns {Object} This event handler
     * @for Api.Events
     */
    this.AddWait = function (key, functionCall, params) {
        var $this = this;

        callerList.push(function () {
            $this.CurrentKey = key;

            var paramsString = "";
            params.forEach(function (item, index) {
                if (paramsString == "")
                    paramsString += "params[" + index + "]";
                else
                    paramsString += ",params[" + index + "]";
            });

            eval("functionCall(" + paramsString + ");");
        });

        return $this;
    };

    /**
     * Execute the next item in the queue
     * @method Api.Events.ExecNext
     * @for Api.Events
     */
    this.ExecNext = function () {
        if (callerList.length > 0) {
            var functionCall = callerList[0];
            callerList.splice(0, 1);
            functionCall();
        }
        else
            this.ExecutionDone();
    };

    /**
     * (Override this function) Function called when execution is done.
     * @method Api.Events.ExecutionDone
     * @for Api.Events
     */
    this.ExecutionDone = function () {
    };

    /**
     * (Override this function) Function when execution of function was successful.
     * @method Api.Events.SuccessCall
     * @param {Object} data The data passed to the function
     * @for Api.Events
     */
    this.SuccessCall = function (data) {
    };

    /**
     * (Override this function) Function when execution of function failed
     * @method Api.Events.FailCall
     * @param {Object} err The error in the failure
     * @for Api.Events
     */
    this.FailCall = function (err) {
    };

    /**
     * Function to set for execution done as one unit object
     * @method Api.Events.ExecuteDone
     * @param {Function} functionToSet The function to set for ExecutionDone
     * @return {Object} The event handler
     * @for Api.Events
     */
    this.ExecuteDone = function (functionToSet) {
        this.ExecutionDone = functionToSet;
        return this;
    };

    /**
     * Function to set for successful call of event as one unit object
     * @method Api.Events.Success
     * @param {Function} functionToSet The function to set for SuccessCall
     * @return {Object} The event handler
     * @for Api.Events
     */
    this.Success = function (functionToSet) {
        var $this = this;
        this.SuccessCall = functionToSet;
        return $this;
    };

    /**
     * Function to set for fail call of event as one unit object
     * @method Api.Events.Fail
     * @param {Function} functionToSet The function to set for FailCall
     * @return {Object} The event handler
     * @for Api.Events
     */
    this.Fail = function (functionToSet) {
        this.FailCall = functionToSet;
        return this;
    };

    return this;
};

Web.Events.ExecQueue = function (queue) {
    return new Promise(function (resolve, reject) {
        var $this = this;

        var currentExecIndex = 0;

        var ExecNextItem = function () {
            currentExecIndex++;

            if (currentExecIndex < queue.length) {
                execNext(currentExecIndex);
            } else {
                resolve();
            }
        }

        var execNext = function (currentExecIndex) {
            var params = queue[currentExecIndex][1];
            var functionCall = queue[currentExecIndex][0];
            var paramsString = "";

            params.forEach(function (item, index) {
                if (paramsString == "")
                    paramsString += "params[" + index + "]";
                else
                    paramsString += ",params[" + index + "]";
            });

            var checkNext = function () {
                if (queue[currentExecIndex][2] !== true) {
                    ExecNextItem();
                }
            }
            eval("functionCall(" + paramsString + ").then(function () { checkNext(); }).catch(function (error) { reject(error); });");

            if (queue[currentExecIndex][2] === true) {
                ExecNextItem();
            }
        }

        execNext(currentExecIndex);
    });
};

var listAdd = [];
var events = new Web.Events();

events.ExecutionDone = () => {
  console.log(listAdd);
}

var doQuery = (query) => {
  console.log('Do Query: ', query);
  listAdd.push(query);
  
  events.ExecNext();
}

events.AddWait('Query 1', doQuery, [ 'Query 1' ]);
events.AddWait('Query 2', doQuery, [ 'Query 2' ]);
events.ExecNext();