Calling one function node from another function node

To simplify flows, I would like to call a function node f2 and send a message from f2, from function node f1. What is your opinion of the following solution?

[
    {
        "id": "e0daef4e151b606a",
        "type": "inject",
        "z": "657242a17ce34e01",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 500,
        "y": 360,
        "wires": [
            [
                "5c4a27309369d270"
            ]
        ]
    },
    {
        "id": "5c4a27309369d270",
        "type": "function",
        "z": "657242a17ce34e01",
        "name": "print",
        "func": "var a = global.get(\"a\")();\na.f1();\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 690,
        "y": 360,
        "wires": [
            []
        ]
    },
    {
        "id": "882e52c58f558266",
        "type": "function",
        "z": "657242a17ce34e01",
        "name": "f1",
        "func": "let a = {};\na.f1 = function() {\n    node.warn(\"Hello world\");\n}\n\nglobal.set(\"a\", function () {\n    return a;\n});\n\n\n\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 690,
        "y": 300,
        "wires": [
            [
                "9a7c3d0aca152e65"
            ]
        ]
    },
    {
        "id": "ec9b3b646962f57c",
        "type": "inject",
        "z": "657242a17ce34e01",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 510,
        "y": 300,
        "wires": [
            [
                "882e52c58f558266"
            ]
        ]
    },
    {
        "id": "9a7c3d0aca152e65",
        "type": "debug",
        "z": "657242a17ce34e01",
        "name": "debug 55",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 880,
        "y": 300,
        "wires": []
    }
]

I wouldn't say this is encouraged behaviour, as this steers away from the flow concept, of what Node RED is designed for - but that is just my opinion.

I would maybe look at using Link call nodes, or subflows, if you need to often refer to a portion of your flow, instead of using globals to try and achieve it.

I think it's a bad plan to use a global variable to store a fragment of code.
Two years later and on another tab entirely you reassign the value of your carefully and explicitly named variable "a", breaking the original flow.
Doing it just to simplify the appearance of the flow is bonkers. The flow might look simpler but it no longer displays how the code works.

As @marcus-j-davies says, you can put "subroutine" flow extracts out of sight on another tab and use link nodes to call them and return values.

1 Like

Link Call nodes are relatively easy to start using.

[{"id":"13bf0454879264de","type":"inject","z":"2d7bf6e3.84c97a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"10","payloadType":"num","x":470,"y":695,"wires":[["e3b005377aff24c0"]]},{"id":"e3b005377aff24c0","type":"link call","z":"2d7bf6e3.84c97a","name":"","links":["4c110cc77e213f4f"],"linkType":"static","timeout":"30","x":700,"y":700,"wires":[["a06808c6f40502d7"]]},{"id":"a06808c6f40502d7","type":"debug","z":"2d7bf6e3.84c97a","name":"debug 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":875,"y":700,"wires":[]},{"id":"8bfb66f253a20896","type":"inject","z":"2d7bf6e3.84c97a","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"20","payloadType":"num","x":470,"y":745,"wires":[["85184fe372f34419"]]},{"id":"85184fe372f34419","type":"link call","z":"2d7bf6e3.84c97a","name":"","links":["4c110cc77e213f4f"],"linkType":"static","timeout":"30","x":700,"y":750,"wires":[["3792dc5ee559c185"]]},{"id":"3792dc5ee559c185","type":"debug","z":"2d7bf6e3.84c97a","name":"debug 3","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":875,"y":750,"wires":[]},{"id":"4081b883db460046","type":"group","z":"2d7bf6e3.84c97a","name":"Sub Routine","style":{"label":true},"nodes":["508dccf7aaf6f262","4c110cc77e213f4f","9477fcf9c93e5d4a"],"x":389,"y":849,"w":552,"h":82},{"id":"508dccf7aaf6f262","type":"function","z":"2d7bf6e3.84c97a","g":"4081b883db460046","name":"Some subroutine (n * 10)","func":"msg.payload = msg.payload * 10\nreturn msg","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":715,"y":890,"wires":[["9477fcf9c93e5d4a"]]},{"id":"4c110cc77e213f4f","type":"link in","z":"2d7bf6e3.84c97a","g":"4081b883db460046","name":"My Subroutine","links":[],"x":495,"y":890,"wires":[["508dccf7aaf6f262"]],"l":true},{"id":"9477fcf9c93e5d4a","type":"link out","z":"2d7bf6e3.84c97a","g":"4081b883db460046","name":"link out 18","mode":"return","links":[],"x":900,"y":890,"wires":[]}]

Further more, a function node in your subroutine for example, can latch onto its own context

1 Like

The problem is that while Node Red is very intuitive, it does not scale very well. I’m using Node Red for building automation. With a hundred or so actuators , the Node Red flow-based interface becomes so glutted that it is no longer usable. I understand the solution is opaque, but it serves the purpose of eliminating a large number of connectors and input/output nodes.

You can get away with that as long as you use memory context. If you use disk or database for persistent context, then the functions are unlikely to be serialisable to storage and it won't work.

As the others have said it is also something of an anti-pattern in that the whole point of the flow approach is to be able to see the flow of data or events... Yes it can get messy but I think link call nodes should work in the example you mention, as they don't add extra wires to "mess things up" :slight_smile:

At the end of the day though - it is your flow - and if that works for you and you think others in your business can "get it" so that they can maintain it in 6 months time - then totally up to you.

1 Like

You left that wide open Dave! :face_with_hand_over_mouth:

But yes, its true - My daughter should be a loving extension to my family, in reality, she just makes my errands easier

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