Node-Red Message and Object Cloning

message-object-cloningAs previously discussed in the the understanding the message object tutorial messages are passed between nodes using a message object.

And as also discussed that this object is a standard JavaScript object and In JavaScript objects are passed by reference and not by value.



Because of this the node-red documentation advised against reusing the msg object but instead recommended creating a new msg object and or cloning the msg object.

Node-Red will automatically clone message objects under certain circumstances, and this behaviour has changed in node-red 1.0 and is described in this tutorial from the Node-Red creator.

In this tutorial I want to look at the message storage objects like flow and global as you encounter similar problems here and you need to be aware of them.

Below is a very simple flow that creates a drop down list from a list stored in a global array.

It uses a change node to get the global object which is passed to a function node that adds an element to the top of the list.

The flow is taken from a database application that I’m developing.

drop-down-list-flow

The list in the global object initially looks like this:

producer_codes

If I click on the inject node to add the none element to the list and look at the UI I see it displayed on the screen like this.

screen-display

All good it seems to work. However if I look again at the stored global object I see :

producer_code_list-2

You can see it has been added to the global object, but I didn’t do it. You should notice there is no set command used in the function node.

var options=msg.options;
var res=options.unshift("NONE");
msg.options=options;
return msg;

Now if I click on the inject node again I get NONE twice and it I click again I get it three times etc.

This is not what I wanted. So what is happening?

The msg.options is set to the global.producer_codes in the change node and passed into the function node.

The function node receives the msg.options and adds the NONE element to it.

However because the change node actually creates a pointer(reference) to global.producer_codes when I update the msg,options I am actually updating the global.producer_codes.

In order to make this work correctly I need to separate the global.producer_codes from msg.options.

This I do by cloning the msg.options object so our function node now looks like this.

var options=RED.util.cloneMessage(msg.options);
var res=options.unshift("NONE");
msg.options=options;
return msg;

Notice the use of the Node-red utility function . RED.util.cloneMessage

Summary

Because JavaScript passes objects by reference you need to be aware that you may need to clone messages and objects in your flows.

Resources:

Related tutorials

Please rate? And use Comments to let me know more
[Total: 0   Average: 0/5]

Leave a Reply

Your email address will not be published. Required fields are marked *