Node.send() vs send() – what's the difference?

I'm trying to understand the difference between using node.send() and send() in a node. This is for the Node-RED MCU Edition exploration, to be able to properly enumerate the full Node-RED behavior. when using the CompatibilityNodeto run nodes.

The "JavaScript file" document Sending Messages section says:

If the node wants to send from inside the input event listener, in response to receiving a message, it should use the send function that is passed to the listener function:

On the page "Creating your first node", the example calls node.send() instead of send() from within the input event listener.

node.on('input', function(msg) {
      msg.payload = msg.payload.toLowerCase();
      node.send(msg);
});

This seems to contradict the "JavaScript file" document which suggests writing it this way:

node.on('input', function(msg, send) {
      msg.payload = msg.payload.toLowerCase();
      send(msg);
});

Finally, the "Writing Functions" page under "Sending messages asynchronously" uses node.send() and it appears this is the only option as there is no send available to "On Message".

Apart from the note in "Sending Messages" in the "JavaScript file" document, it appears acceptable to use node.send() everywhere. What is different about using send()?

Hi @phoddie

This relates to your previous questions about done and the Complete node.

The preferred way is to use send() as that allows the runtime to correlate which arriving message triggered the send.

This blog post explains the difference when it was first introduced: Knowing when a node is done : Node-RED

In the context of a custom (add-in) node, the end result is the same.

The "JavaScript file" docs are more current: If the node wants to send from inside the on input event listener, in response to receiving a message, it should use the send function that is passed to the listener function:

This is the "newer" api that supports the complete node via the done callback.

let node = this;
this.on('input', function(msg, send, done) {
    // For maximum backwards compatibility, check that send exists.
    // If this node is installed in Node-RED 0.x, it will need to
    // fallback to using `node.send`
    send = send || function() { node.send.apply(node,arguments) }

    msg.payload = "hi";
    send(msg);

    if (done) {
        done();
    }
});

The issue (in the case of mcu) may be that some contrib nodes (and indeed some of the older built in nodes) have not yet been updated to the new API so there is a mix throughout the ecosystem.

In essence they are equivalents

  • node.send(msg) == send(msg)
  • node.error(err, msg) == done(err)

I am not certain how or if this will have any bearing or impact on design of mcu at this point (would need a use case)

Some nodes do not have an input & therefore no (send, done) functions passed in. In these cases node.send and node.error are the only option.

For some nodes, it may not make sense to utilise the complete node (e.g. a cron type node with an endless pulse is never really complete)


That is correct.
An important aspect to the function node is that it is executed in a VM sandbox and is isolated from the actual runtime. The send and done functions are mapped to an object named node along with some other properties. To be clear, the function code entered by a user is wrapped as below...

var results = null; results = (async function (msg, __send__, __done__) {
    var __msgid__ = msg._msgid; 
    var node = { id: __node__.id, name: __node__.name, path: __node__.path, outputCount: __node__.outputCount, log: __node__.log, error: __node__.error, warn: __node__.warn, debug: __node__.debug, trace: __node__.trace, on: __node__.on, status: __node__.status, send: function (msgs, cloneMsg) { __node__.send(__send__, __msgid__, msgs, cloneMsg); }, done: __done__ };
    // user code start
    msg.payload = new Date().toString()
    node.send(msg)
    node.done()
    // user code end
})(msg, __send__, __done__);

Other info of importance as you explore the MCU implementation...


Hope these disjointed replies are of some use.

PS, keep up the great work :+1:

2 Likes

@Steve-Mcl and @knolleary – thank you both very much for your replies. They definitely help. I think I'm starting to understand. I need a little more time to think and experiment before asking more about this topic.

FWIW, most of Node-RED has been remarkably straightforward to follow. Every large system has some complex parts; send and done seem to be that for Node-RED. :wink: From your comments, part of that is to maintain backwards compatibility.