0

I'm a Javascript newbie, and I'm building small nodeJS programs to learn more about Javascript.

I have an issue with my code that I cannot seem to solve. My program basically looks like this.

While (exitProgram === false){

   // user input

   // If user input is 'save', save a file to the disk
   // If user input is 'exit', exitProgram = false

};

The problem is that the file only saves to the disk after the while loop is exited. I know this has something to do with Asynchronous execution of the writefile function, but I don't know how to make sure the file is saved in the loop (or other solutions).

Do you have any ideas or suggestions on how to do this?

This is my code so far:

'use strict';

const prompt = require('prompt-sync')();
const fs = require('fs');

const filePath = 'c:/documents/writefiletest/';
let fileName = 'characters.txt';

var allCharacters = [];


let buildCharacter = function () {

    let name = null, strenght = null, hp = null;

    name = prompt('You want to make a new Character. What is the name? ');
    strenght = prompt('And the strenght? ');
    hp = prompt('And lastly the hitpoints? ');

    let newChacacter = {
        name: name,
        strenght: strenght,
        hp: hp
    };

    console.log('You created ' + name + ' with ' + hp + ' hitpoints and ' + strenght + ' strenght.')
    return newChacacter;
}


let ShowAllCharacters = function (allCharactersToShow) {

    let i;

    if (allCharactersToShow.length === 0) {
        console.log('There are no characters to return. \n')
        return false;
    };

    for (i = 0; i < allCharactersToShow.length; i++) {
        console.log(i + ': ' + allCharactersToShow[i].name + ' has ' + allCharactersToShow[i].strenght + ' strenght and ' + allCharacters[i].hp + ' hitpoints.');

    };
};


let saveToFile = function (data) {

    if (data.length == 0) {
        saveFilemessage.sucess = false;
        saveFilemessage.message = 'There are no characters to save';
        return;
    };

    fs.writeFile(filePath.concat(fileName), JSON.stringify(data), function (err) {
        if (err) {
            console.log("this is the error " + err);
            return;
        } else {
            console.log('File saved to ' + filePath.concat(fileName));
            return;
        };
    });
}

// Main Loop
while (!exitProgram) {

    let userCommand = null;

    console.log('\nWhat would you like to do? (New) (Show All) (Save To File) (Open File) (Exit)');
    userCommand = prompt('');

    switch (userCommand.toLowerCase()) {
        case 'new':
        case 'n':
            allCharacters.push(buildCharacter());
            break;

        case 'show all':
        case 'show':
            ShowAllCharacters(allCharacters);
            break;

        case 'exit':
        case 'e':
            exitProgram = true
            break;

        case 'save to file':
        case 'save':
        case 's':
            saveToFile(allCharacters);
            break;
        case 'open file':
        case 'o':
            console.log('Still to build open file function here');
            break;

    };
    setTimeout(function () { return }, 0);

};

Thanks!

1
  • You could use writeFileSync() instead. Commented Feb 3, 2021 at 21:23

1 Answer 1

2

When you call the writeFile it works asynchronously and you can not wait for it finished with callbacks.

In the JS world there several ways to solve this issue.

1. Use .writeFileSync

writeFileSync is synchronous and it will wait until the saving is done.

function saveToFile(data) {

    if (data.length == 0) {
        saveFilemessage.sucess = false;
        saveFilemessage.message = 'There are no characters to save';
        return;
    };

    fs.writeFileSync(filePath.concat(fileName), JSON.stringify(data));
}

2. Use async/await with Promise

Basically you can make your functions as promises and wait for them to be finished. It requires some knowledge to use them. Here is a simple example for you.

function saveToFile(data) {
   return new Promise((resolve, reject) => {
    if (data.length == 0) {
        saveFilemessage.sucess = false;
        saveFilemessage.message = 'There are no characters to save';
        resolve(false);
    };

    fs.writeFile(filePath.concat(fileName), JSON.stringify(data), function (err) {
        if (err) {
            console.log("this is the error " + err);
            reject(false);
        } else {
            console.log('File saved to ' + filePath.concat(fileName));
            resolve(true);
        };
    });
   })
}


async function callMyFunction(){
   await saveToFile('yourData');
}

3. Stay in the loop until callback is called (don't use this JS is not C++)

let saveToFile = function (data, doneFn) {

    if (data.length == 0) {
        saveFilemessage.sucess = false;
        saveFilemessage.message = 'There are no characters to save';
        doneFn(false);
    };

    fs.writeFile(filePath.concat(fileName), JSON.stringify(data), function (err) {
        if (err) {
            console.log("this is the error " + err);
            doneFn(false);
        } else {
            console.log('File saved to ' + filePath.concat(fileName));
            doneFn(true);
        };
    });
}

// Main Loop
while (!exitProgram) {

    let userCommand = null;

    if(userCommand !== "SAVING"){
      console.log('\nWhat would you like to do? (New) (Show All) (Save To File) (Open File) (Exit)');
      userCommand = prompt('');
    }


    switch (userCommand.toLowerCase()) {
        case 'new':
        case 'n':
            allCharacters.push(buildCharacter());
            break;

        case 'show all':
        case 'show':
            ShowAllCharacters(allCharacters);
            break;

        case 'exit':
        case 'e':
            exitProgram = true
            break;

        case 'save to file':
        case 'save':
        case 's':
            userCommand = 'SAVING';
            saveToFile(allCharacters, function(res){
              if(res){
                 console.log('Saving is done');
              }else{
                console.log('Saving is failed');
              }
              userCommand = null;
            });
            break;
        case 'open file':
        case 'o':
            console.log('Still to build open file function here');
            break;

    };
    setTimeout(function () { return }, 0);
};
Sign up to request clarification or add additional context in comments.

1 Comment

What is setTimeout(...) supposed to do? 3. doesn't work at all and never will, because two things cannot execute at the same time (you can't set userCommand = null while the loop is running)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.