A strange problem on fs.stat usage inside function node

Run into a strange problem: Calling fs.stat() function inside Node-RED's function node, msg.payload can be updated correctly, depending on whether the file exists or does not exist. But the variable tt is undefined, instead of being 0 or 1. What could be the issue?

var tt;

fs.stat('/home/pi/testfile', function(err) {
    if (err) {
      msg.payload = false      // testfile does not exist
      tt=0;
    } else {
      msg.payload = true     // testfile exists
      tt=1;
    }
});
msg.tt=tt;  // tt is always undefined 
return msg;

Please see the debug output:

The test flow is here:

[{"id":"d91f5f9882284a25","type":"function","z":"d3c8b30753c78d12","name":"Tests","func":"var tt;\n\nfs.stat('/home/pi/testfile', function(err) {\n    if (err) {\n      msg.payload = false      // testfile does not exist\n      tt=0;\n    } else {\n      msg.payload = true     // testfile exists\n      tt=1;\n    }\n});\nmsg.tt=tt;\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[{"var":"fs","module":"fs"}],"x":1050,"y":1440,"wires":[["161e8c033aaf1a33"]]},{"id":"67ccbdbb6a93218e","type":"inject","z":"d3c8b30753c78d12","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":900,"y":1440,"wires":[["d91f5f9882284a25"]]},{"id":"161e8c033aaf1a33","type":"debug","z":"d3c8b30753c78d12","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1230,"y":1440,"wires":[]}]

I think you will find that fs.stat is an asynchronous function. So the msg.tt=tt line is executed immediately and only later is the msg.payload set. If you are seeing the correct output after the node, that is pure coincidence of timing and due to JavaScript passing variables by reference so that the msg object gets updated before you actually reference it in a later node.

Put the final 2 lines of your function node inside the stat callback function and everything should work correctly.

Yes you are correct.

But if putting final two lines of the function node inside the stat callback function, then there is no output returned from the debug node. It caused strange behavior from the console output instead.

Putting "msg.tt=tt " inside works. What could be the reason?
The following is the working code:

fs.stat('/home/pi/testfile', function(err) {
    if (err) {
      msg.payload = false      // testfile does not exist
      msg.tt=0;
    } else {
      msg.payload = true     // testfile exists
      msg.tt=1;
    }
});

return msg;

You might want to do some reading up on asynchronous coding in node.js.

The function attached as a callback to the stat call is run when stat actually returns something useful. Anything outside of that function and after it in the code will run immediately that the function node runs.

fs.stat('/home/pi/testfile', function(err) {
    if (err) {
      msg.payload = false      // testfile does not exist
      msg.tt=0;
    } else {
      msg.payload = true     // testfile exists
      msg.tt=1;
    }
    node.send(msg);
});

node.warn('Ooh! This is output BEFORE the actual message')

Note that while node-red appears to be passing messages around - it really ISN'T! It is passing references to a msg object. That means that the content of the msg object can continue to change - sometimes unexpectedly - due to ongoing async code finally returning something.

Putting the node.send(msg) inside the callback function ensures that it will only output a msg when there is a valid response.

That makes sense.

Can we use await method to wait until the fs.stat finishes processing?
This way, we can put return msg outside the function.

How to do it in the function node?

The docs explain how to send messages asynchronously: Writing Functions : Node-RED

You cannot use return to do that inside an async callback.

My bad, corrected the post to node.send

1 Like

@knolleary Thanks Nick. It would be great to have more examples along with the description.

@TotallyInformation Yes I was about to say the same thing after reading through the description.
Need to use Node.send, otherwise there could be unexpected behavior.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.