1

Here is my node js code:

var ResponseData = { str: "" };

function GetFilesList( FolderName, ResponseData )
{
    fs.readdir( FolderName, GetFilesList_callback );
}

function GetFilesList_callback( Err, Files )
{   
    if( Err ) throw Err;
    for( var Idx in Files )
    {
        var Entry = "File " + Idx + " =" + Files[ Idx ] + "=";
        ResponseData.str += Entry;
        console.log( Entry );
    }
}

After calling GetFilesList() function, ResponseData.str does not contain the file names although I see them in the concole.

Based on answers got here, I modified the functions as following:

function GetFilesList( FolderName, ResponseData )
{
    var prom = new Promise( function( resolve, reject )
             { fs.readdir( FolderName, GetFilesList_callback ) } );
    prom.then( function( Files )
                 {
                    ResponseData.str += "x";
                    console.log( "after_promise" );
                 } )
}

The "then" part is not executed. Strange enough, if a I place a second request to server (i.e. a simply page refresh in browser) I see just then that ResponseData.str has the file names I expect (but not the "x"es).

Gigi
  • 158
  • 11
  • 2
    Possible duplicate of [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – Patrick Roberts Apr 13 '18 at 19:11
  • By the way, am I correct to guess that you mainly use C#? – Patrick Roberts Apr 13 '18 at 19:16
  • @Patrick Roberts You are right, I'm C#, I want now to prepare myself for a career change. What gave me away? :) – Gigi Apr 14 '18 at 08:18
  • TitleCase variable names and open curly brackets on the next line, it's the coding style that visual studio and .NET favor, whereas JavaScript developers tend to use camelCase variable names (except for classes) and open curly brackets on the same line. – Patrick Roberts Apr 14 '18 at 17:23

3 Answers3

1

ResponseData.str DOES contain the files, but you need to keep going with your code inside the callback after the for-loop.

CFrei
  • 3,552
  • 1
  • 15
  • 29
0

Depending on when you're accessing ResponseData, it's possible that you're printing it out before the callback finishes.

To prevent yourself from getting into callback hell and the asynchronous nature of node.js, use promises

a common pattern is the following:

new Promise((resolve, reject) => fs.readdir(foldername, (err, files) => {
    resolve(files)
}).then((files) => {
     //do something with the files
})
Eric Yang
  • 2,678
  • 1
  • 12
  • 18
  • Or just `util.promisify(fs.readdir)(foldername).then(files => { ... }, error => { ... })`, which, by the way, properly rejects errors instead of leaving the promise pending. – Patrick Roberts Apr 13 '18 at 19:17
  • @Eric Yang I have modified the function as I shown in the later edit of my post. Still does not work. – Gigi Apr 14 '18 at 17:50
  • Can you post your complete code in a jsfiddle or something like that so I can try to fix it for you? – Eric Yang Apr 15 '18 at 17:55
0

Let's start with the idea that you are using asynchronous calls wrong.

First of all, it is a very bad idea to write functions that use data externally, especially when asynchronous is involved (let alone function handlers).

Please brush on your async coding knowledge. You should start by having your functions only work with passed in variables, nothing from outside (no side effects). While your small example might work eventually, you can not build a good code base going forward like this.

Second, as others pointed out, you are probably calling GetFilesList and then printing the result. So your call to GetFilesList starts an asynchronous operation and then the function ends (in that it exists). But this doesn't mean it finished what it intended to do, so in the next line you are printing ResponseData and get the surprise that it is empty. After you print it, the disk operation would be done and then your callback is called and at that point your data is filled out, your question should be "when to know" or "how to wait" until it gets filled. You are mixing synchronous logic with async logic, which is totally okay and it happens to everyone at first.

You don't need promises to fix this problem, promises is the preferred way, but if you are just starting async coding, I personally would recommend callbacks until you understand it 100% and then move over to promises.

Have a look at this code, I added main to try to help you understand the flow.

const fs = require("fs");

function getFilesList(FolderName, callback) {
  fs.readdir(FolderName, callback);
}

function main(callback) {
  getFilesList(".", function(err, files) {
    if(err) {
      return callback(err);
    }

    const responseData = {str: ""};

    for(const Idx in files) {
      const Entry = "File " + Idx + " =" + files[Idx] + "=";
      responseData.str += Entry;
      console.log(Entry);
    }

    callback(null, responseData);
  });
}

main(function(err, responseData) {
  if(err) {
    console.log("Error:", err);
  } else {
    console.log(responseData);
  }
});
Ralph
  • 1,480
  • 11
  • 16
  • The problem is that I use in my nodejs server this: http.createServer( OnRequest ).listen( 8873); In the function function OnRequest( Request, Response ) I have to provide an answer synchronously, so I would have to wait for answers to come from asynchronous part in order to pass the response to OnRequest function. – Gigi Apr 23 '18 at 08:52
  • That's exactly how it is designed to work. Your http request will wait until you get back your data... asynchronously, You should not provide them synchronously. So something like this: function OnRequest(req, res) { getFilesList(".", function(err, files) { if(err) { return res.end("An error occurred"); } const responseData = {str: ""}; for(const Idx in files) { const Entry = "File " + Idx + " =" + files[Idx] + "="; responseData.str += Entry; console.log(Entry); } res.end(responseData); // your success }); } – Ralph Apr 23 '18 at 14:19
  • A quick internet search for async concept got me there, I hope they will help: https://blog.risingstack.com/node-hero-async-programming-in-node-js/ https://nodejs.org/en/docs/guides/blocking-vs-non-blocking/ – Ralph Apr 23 '18 at 14:24
  • I think I got it now. I have now my first NodeJS "asynchronous" server up and running. :) And I think to myself, what a wonderful world... :))) – Gigi Apr 24 '18 at 12:06
  • That's great. Good luck and drop me a message if you need anything else. Always happy to help with nodejs. – Ralph Apr 24 '18 at 14:21