0

I'm entirely new to NodeJS and this problem has been bugging me for days now. I'm pulling my hairs to find a working solution. I'm trying to get information from the database and pass it to a text file where I later read from it. I cannot do it sequentially. It always reads it first and then creates it. I don't know what way I should take to overcome the issue. Any working solution/ways will help tremendously.

My connection file that retrieves information from the database:

this.getInfo = function() {
return new Promise(function(resolve, reject){
  db.query('SELECT ai_code from user_code',
    function(err,rows){
      if(err)
        reject(err);
      resolve(rows);
  });
 });
}

module.exports = 
{
    getInfo: this.getInfo
}

Functions that calls the method to receive data.

function team1Code(){
    db.getInfo().then(function(result){
       var code = JSON.stringify(result[0]);
       var c = json2plain(code, options);
       c = c.replace('Ai_code:','');
       fs.writeFile('./scr1.js', c, { overwrite: true, encoding: 'ascii' },function (err) {
        if (err) return console.log(err);
       });
    });
}
function team2Code(){
    db.getInfo().then(function(result){
        var code = JSON.stringify(result[1]);
        var c = json2plain(code, options);
        c = c.replace('Ai_code:','');
        fs.writeFile('./scr2.js', c, { overwrite: true, encoding: 'ascii' },function (err) {
            if (err) return console.log(err);
        });
    });
}

Finally, this is where we try to read the content of the files.

vmHandler.init = function(apiValues) {
    team1Code();
    team2Code();
  // Team 1
    try{
      vmHandler.team1.scriptCode = fs.readFileSync('./scr1.js');
      vmHandler.team1.script = new vm.Script(vmHandler.team1.scriptCode);
      vmHandler.team1.sandbox = { api: new Api(apiValues, 1) }
      vmHandler.team1.context = new vm.createContext(vmHandler.team1.sandbox);
    }catch(err){}
  // Team 2
    try {
      vmHandler.team2.scriptCode = fs.readFileSync('./scr2.js');
      vmHandler.team2.script = new vm.Script(vmHandler.team2.scriptCode);
      vmHandler.team2.sandbox = { api: new Api(apiValues, 2) }
      vmHandler.team2.context = new vm.createContext(vmHandler.team2.sandbox);
    } catch(err) {
      console.log("ERROR: " + err);
    }
};
knoxgon
  • 1,070
  • 2
  • 15
  • 31

2 Answers2

1

The approach you are taking is slightly unfavorable since the function calls team1Code(); team2Code(); doesn't make sure to accomplish before the next try-catch block gets executed. This is because both the calls are asynchronous hence the next lines get executed before they finish even though they are working with promises. promises themselves are asynchronous, what they make easy is all the code inside any then won't be executed until the promises get settled but the rest of the code will be executed as usual. So, here is the way to do your tasks with updated code.

function writeFile(fileName,data){
    return new Promise(function(resolve, reject){
        var code = JSON.stringify(data);
        var c = json2plain(code, options);
        c = c.replace('Ai_code:','');
        fs.writeFile(fileName, c, { overwrite: true, encoding: 'ascii' },function (err) {
            if(err)
                reject(err);
            resolve();
        });
    })
}
//Finally, this is where we try to read the content of the files.

vmHandler.init = function(apiValues) {
    var files = ['./scr1.js','./scr2.js'];
    db.getInfo().then(function(result){
        var allPromise = [];
        for(var key in files){
            allPromise.push(writeFile(files[key], result[key]));
        }
        return Promise.all(allPromise);
    }).then(function(res){
      // Team 1
        try{
          vmHandler.team1.scriptCode = fs.readFileSync('./scr1.js');
          vmHandler.team1.script = new vm.Script(vmHandler.team1.scriptCode);
          vmHandler.team1.sandbox = { api: new Api(apiValues, 1) }
          vmHandler.team1.context = new vm.createContext(vmHandler.team1.sandbox);
        }catch(err){}
      // Team 2
        try {
          vmHandler.team2.scriptCode = fs.readFileSync('./scr2.js');
          vmHandler.team2.script = new vm.Script(vmHandler.team2.scriptCode);
          vmHandler.team2.sandbox = { api: new Api(apiValues, 2) }
          vmHandler.team2.context = new vm.createContext(vmHandler.team2.sandbox);
        } catch(err) {
          console.log("ERROR: " + err);
        }
    });
};
nurulnabi
  • 459
  • 3
  • 11
  • Thanks a lot @nurulnabi for showing the courage and putting the time to redecorate the code. It almost works now but there is a slight problem with another part of the code that receives the code after `init`. I can't seem to bypass it even before this problem occurred. That part of the program runs parallel and somehow, nothing gets returned from `init` to that part of the code. It ends up as undefined. `api` is undefined as if it never received anything from the file. The code is at the following link where you can see the part. https://hastebin.com/afenaqojut.js – knoxgon Apr 11 '17 at 11:47
  • all the problems is happening because of async nature of node.js, somewhere in your project you may be calling `vmHandler.init` and after this you may be calling `vmHandler.runVMs` unaware of the fact that `vmHandler.init` itself will run async, as I told that promises are async in nature they can only assure that the codes written in `then` will be executed after the promise got resolved the code after the `vmHandler.init` call will run asynchronously without waiting for the `vmHandler.init` to finish. so for that you need to use callback in `vmHandler.init` or make use of promise everywhere. – nurulnabi Apr 11 '17 at 13:09
  • you better use callback in `vmHandler.init` to make it synchronous with the other function calls which need it to finish before they get called or otherwise you need to make every function return promise and then chain with `then` one after the other to accomplish your tasks. – nurulnabi Apr 11 '17 at 13:13
  • Sorry for the delay response @nurulnabi I did use a callback in that but now I get the same error. I don't even know what paths I can take. This is driving me crazy. Sorry for bugging you with this awful problem but I can't even comprehend it. I would be must thankful if you could take a look at the following code or perhaps correct it for me. I also included engine file which it calls my vmhandler.init from. https://hastebin.com/zexurivoli.js – knoxgon Apr 12 '17 at 08:28
  • `vmHandler.init(game.getGameInfo(), function(err){ //rest of your code which must be executed once vmHandler.init completes its execution });` whatever code you are putting after this call put all those in the callback here. – nurulnabi Apr 12 '17 at 09:28
  • rather than returning the callback from `vmHandler.init` just you need to call that there in the last `then`. – nurulnabi Apr 12 '17 at 09:29
  • you should use callbacks in every function which is doing async operation like db operation or anything else and put the next bit of code inside that call back and son on. otherwise use promise in every function. That's how you are gonna tackle your problem. – nurulnabi Apr 12 '17 at 10:17
0

In the wmHandler.init function, you are starting 2 asynchronous operations (querying and storing) and reading from the files that the aforementioned async operations should write.

However, the file reading is performed right after the 2 async operations are started. Therefore, it is expected that the files are read before written.

To resolve this, make team1Code and team2Code return Promises of their own, and do not read the files until they have been written.

team1Code().
    .then(team2Code)
    .then(readFiles)

Where readFiles is the function that does the file reading, and team1Code, team2Code return Promises that resolve when the files are written.

This answer explains the asynchronous callbacks in Javascript.

Community
  • 1
  • 1
Andre T
  • 479
  • 5
  • 5
  • Thanks for the reply Andre. I can't really success with any promise/callbacks. I made a callback function inside readFileSync (which I later renamed to readFile for callback operation). But it returns empty string at the end. I just don't know what to do. I've been crawling all over the internet but no luck so far. – knoxgon Apr 11 '17 at 06:49