Deep Copy of Arrays and Objects using RED.util.cloneMessage()

Having opened my eyes to the need to be very intentional on if I am using a copy of a msg or a reference to the message, I have started using RED.util.cloneMessage() when I need a copy to manipulate that won't maninpulate the original msg.

Since messages are objects, getting a clone of the msg seems like a special case of the more general problem of needing to clone objects/arrays. From what I have found the general case seems to be referred to in the general Javascript world as making a Deep copy. I have done some (minor) experimentation inside a Node-RED function node and found that RED.util.cloneMessage() seems to hand the general case and not just the clone message case. Here is some code that shows it working:

a = [1,[2,3]]
c =  RED.util.cloneMessage(a)
    /*
    Alternate more standard Javascript way of making a deep copy of a 
    c = JSON.parse(JSON.stringify(a))
    */
c[1].push(4)
node.warn(a)
node.warn(c)

With these results:
image

I have 2 resulting questions for those more knowledgeable than me:

  1. Other than the obvious drawback that code using RED.util.cloneMessage() would not inherently work outside of the Node-RED environment, what is the drawback of using it whenever a deep copy (clone) is needed?
  2. In the context of Node-RED development are there efficiency differences between using RED.util.cloneMessage() vs JSON.parse(JSON.stringify()) shown in the commented part of my code above?

I also wanted to note, that the JSON.parse(JSON.stringify()) version has some weaknesses that are described here and so might be a bad comparison. That page suggests using Lodash. For my simple case, using a utility library is a little to many extra steps

1 Like

If you dig into the util.js code inside the Node-RED source you will find that it requires... const clonedeep = require("lodash.clonedeep");

2 Likes

As Dave points out, cloneMessage uses the lodash.clonedeep module under the covers.

The JSON.parse(JSON.stringify()) method will only work for JSON encodable values - as the article you link to highlights. The fact we use lodash under the covers means we can handle lots of the common JavaScript object types that cannot be serialised to JSON, such as Date.

The cloneMessage function also has built-in awareness of msg.req and msg.res - properties sent by the HTTP In node that cannot be otherwise cloned.

3 Likes

Based on this, then it seems the best pattern would be to use RED.util.cloneMessage() in Node-RED to take advantage of both lodash.clonedeep and the Node-RED specific additional coding under the covers and probably to use lodash.clonedeep elsewhere.

Thanks for the feedback both of you.