# Defining and reuse a "classic" JS function

**URL:** <https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372>\
**Category:** General\
**Created:** [6 October 2019 07:22 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372 "2019-10-06T07:22:29Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![BruceFeuillette](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/brucefeuillette/32/12869_2.png) [@BruceFeuillette](https://discourse.nodered.org/u/BruceFeuillette)\
**Post date:** [6 October 2019 07:22 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/1 "2019-10-06T07:22:29Z")

</div>

Hello !  
I'm a bit lost in node-red, maybe I didn't wired the right nodes together... 😅

**The context**  
I'm working with LoRa sensors that send hexa code in the payload. Those datas are specific informations based on the "port" they use : 5 is battery info, 9 is an alive message, 30 is opening counter + temperature + humidity. So each one must be treated differently.  
As we're three to work on the project, I wanted to have a clear flow, so everyone could see what happens.  
I have a NR Function node by port used and each hexa data in the payload is converted specifically.

**The question**  
As I'm lazy, like every programmer I guess, I wanted to create some hex2bin, hex2dec, hex2float functions and reuse them in my flow, without redefining them each time. They should be called in every Function node.  
But I didn't find how to do this... And as Node-Red is using the concept of "_Function_", it's hard to find answers on Internet for "_JS function_" ! 🙂

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [6 October 2019 07:26 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/2 "2019-10-06T07:26:16Z")

</div>

Create 3 subflows for hex2bin, hex2dec & hex2float

A subflow is kinda like a reusable function.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [6 October 2019 07:28 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/3 "2019-10-06T07:28:26Z")

</div>

If you wanted to you could create just one subflow (that does all three operations) and you specify which operation by `topic` or by a subflow property.

Have a play, see what best suits your needs.

---

<div class="post-metadata">

**Author:** ![afelix](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/afelix/32/9743_2.png) [@afelix](https://discourse.nodered.org/u/afelix)\
**Post date:** [6 October 2019 07:33 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/4 "2019-10-06T07:33:37Z")

</div>

Or a different approach, write them as a JavaScript module and make it available for use in functions through functionGlobalContext, see the configuration documentation

---

<div class="post-metadata">

**Author:** ![bakman2](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bakman2/32/6207_2.png) [@bakman2](https://discourse.nodered.org/u/bakman2)\
**Post date:** [6 October 2019 07:35 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/5 "2019-10-06T07:35:08Z")

</div>

> But I didn't find how to do this... And as Node-Red is using the concept of " _Function_ ", it's hard to find answers on Internet for " _JS function_ " !

You can search for `javascript hex2bin`, you will find something like

```auto
function hex2bin(hex){
    return ("00000000" + (parseInt(hex, 16)).toString(2)).substr(-8);
}

```

For use in node-red, use a function node, something like:

```auto
function hex2bin(hex){
    return ("00000000" + (parseInt(hex, 16)).toString(2)).substr(-8);
}

input = msg.payload
output = hex2bin(input)

return {payload:output} 

```

---

<div class="post-metadata">

**Author:** ![BruceFeuillette](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/brucefeuillette/32/12869_2.png) [@BruceFeuillette](https://discourse.nodered.org/u/BruceFeuillette)\
**Post date:** [6 October 2019 07:51 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/6 "2019-10-06T07:51:52Z")

</div>

I already have the functions, I just want to know how to reuse them in the whole flow, without copy/paste them. 🙂  
Like an include, if you prefer.

---

<div class="post-metadata">

**Author:** ![BruceFeuillette](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/brucefeuillette/32/12869_2.png) [@BruceFeuillette](https://discourse.nodered.org/u/BruceFeuillette)\
**Post date:** [6 October 2019 07:52 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/7 "2019-10-06T07:52:49Z")

</div>

I'll give a try to a subflow and the functionGlobalContext and let you know. 🙂  
A lot of reading for this sunday !

---

<div class="post-metadata">

**Author:** ![cflurin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/cflurin/32/29_2.png) [@cflurin](https://discourse.nodered.org/u/cflurin)\
**Post date:** [6 October 2019 07:57 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/8 "2019-10-06T07:57:58Z")

</div>

Have a look here:

> [@Use function multiple times](https://discourse.nodered.org/t/use-function-multiple-times/7280/3):
>
> One approach would be to use the global.set() with the memory module. store your function in a global variable: global.set('sum', function(a, b) { return a + b; }, 'memoryOnly'); use your function: msg.payload = global.get('sum', 'memoryOnly')(2, 3); return msg; Note: you need this setting in the settings.js: contextStorage: { default: { module:"localfilesystem" }, memoryOnly: { module: "memory" } }, Flow: [{"id":"4ac…

---

<div class="post-metadata">

**Author:** ![bakman2](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bakman2/32/6207_2.png) [@bakman2](https://discourse.nodered.org/u/bakman2)\
**Post date:** [6 October 2019 07:59 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/9 "2019-10-06T07:59:09Z")

</div>

Ah ok misunderstood then subflow or functionGlobalContext are good ways to go.

---

<div class="post-metadata">

**Author:** ![BruceFeuillette](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/brucefeuillette/32/12869_2.png) [@BruceFeuillette](https://discourse.nodered.org/u/BruceFeuillette)\
**Post date:** [6 October 2019 09:33 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/10 "2019-10-06T09:33:40Z")

</div>

Works well !  
I've done a mix with a subflow. 🙂  
My subflow, called "JS classic function", has an Inject node "trigger-on-start" and 2 functions (hex2bin and hex2dec) wired to it, so it's executed at 0.1s after Node-Red start and the functions are in memory.  
I just had tyo had my Subflow to the flow to enable the classic JS functions.

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/5/57cce4aa3681311cc93e1bc1c45b23e5b682659a.png)  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/4/44ab64f717c2466de642bbf57d394e8ff96d10f6.png)

Here's the code, if somebody is trying to do the same. 🙂

```auto
[{"id":"f9586397.5973","type":"subflow","name":"JS functions","info":"","category":"","in":[],"out":[],"env":[],"color":"#DDAA99"},{"id":"7d7eee51.7878a8","type":"function","z":"f9586397.5973","name":"hex2dec","func":"global.set('hex2dec', function(hexa) {\n return parseInt(hexa, 16);\n}, 'memoryOnly');\n","outputs":1,"noerr":0,"x":400,"y":80,"wires":[[]]},{"id":"2012dbe6.92df34","type":"function","z":"f9586397.5973","name":"hex2bin","func":"global.set('hex2bin', function(hex) {\n return (\"00000000\" + (parseInt(hex, 16)).toString(2)).substr(-8);\n}, 'memoryOnly');","outputs":1,"noerr":0,"x":400,"y":40,"wires":[[]]},{"id":"df964a73.694328","type":"inject","z":"f9586397.5973","name":"Trigger on start","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":140,"y":40,"wires":[["2012dbe6.92df34","7d7eee51.7878a8"]]},{"id":"35ca0b72.bb35ec","type":"tab","label":"Test functions","disabled":false,"info":""},{"id":"92ec9209.762ac","type":"inject","z":"35ca0b72.bb35ec","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":120,"wires":[["3c377357.2eb52c"]]},{"id":"3c377357.2eb52c","type":"function","z":"35ca0b72.bb35ec","name":"Test 2 functions","func":"msg.payload = {\n bin: global.get('hex2bin', 'memoryOnly')(\"0x777\"), \n dec: global.get('hex2dec', 'memoryOnly')(\"0x777\") \n}\nreturn msg;","outputs":1,"noerr":0,"x":340,"y":120,"wires":[["867de411.01ff3"]]},{"id":"ce6ea1e.e1e90e","type":"subflow:f9586397.5973","z":"35ca0b72.bb35ec","name":"JS Classic functions","env":[],"x":170,"y":60,"wires":[]},{"id":"867de411.01ff3","type":"debug","z":"35ca0b72.bb35ec","name":"Full msg","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":520,"y":120,"wires":[]}]

```

---

<div class="post-metadata">

**Author:** ![cflurin](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/cflurin/32/29_2.png) [@cflurin](https://discourse.nodered.org/u/cflurin)\
**Post date:** [6 October 2019 09:49 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/11 "2019-10-06T09:49:30Z")

</div>

I don't think you need the subflow, since you use it to set the global functions once.  
I'd use a function node instead.

---

<div class="post-metadata">

**Author:** ![bakman2](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bakman2/32/6207_2.png) [@bakman2](https://discourse.nodered.org/u/bakman2)\
**Post date:** [6 October 2019 10:04 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/12 "2019-10-06T10:04:48Z")

</div>

That is an odd implementation of a subflow, but if it works, it works 😉

"Normally" you would add an input and an output and route your message through the "node" (read subflow).

---

<div class="post-metadata">

**Author:** ![BruceFeuillette](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/brucefeuillette/32/12869_2.png) [@BruceFeuillette](https://discourse.nodered.org/u/BruceFeuillette)\
**Post date:** [6 October 2019 10:21 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/13 "2019-10-06T10:21:01Z")

</div>

The subflow is just to have a "cleaner" view. 🙂  
Our first flow is very messy for the moment as we're new to Node-Red and we're trying to sell our project to our Directors. So it's straight to the result instead of a beautiful and well think code. There's a lot of functions, templates, gauges and other nodes. Maybe we should think differently...  
As our LoRa sensor aren't well known, I have to write a full "deciphering" module. So it will probably looks way different at the end !

Anyway, many thanks for your help !

---

<div class="post-metadata">

**Author:** ![kuema](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/kuema/32/6542_2.png) [@kuema](https://discourse.nodered.org/u/kuema)\
**Post date:** [7 October 2019 04:35 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/14 "2019-10-07T04:35:03Z")

</div>

Similar to my approach here: [Importing function from another node](https://discourse.nodered.org/t/importing-function-from-another-node/15885/6)

Just for completeness. 🙂

---

<div class="post-metadata">

**Author:** ![krzydec](https://avatars.discourse-cdn.com/v4/letter/k/a5b964/32.png) [@krzydec](https://discourse.nodered.org/u/krzydec)\
**Post date:** [26 April 2022 12:32 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/15 "2022-04-26T12:32:19Z")

</div>

Hello.

I'm also trying to reuse functions by recalling them from the context store.  
Example:

```auto
[{"id":"728cb92b07d335fb","type":"inject","z":"866282f4.d0922","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"date","x":440,"y":2840,"wires":[["487bcdf41f1bddf6"]]},{"id":"487bcdf41f1bddf6","type":"function","z":"866282f4.d0922","name":"func test","func":"\nglobal.set('lockCountdown', function lockCountdown() {\n //node = this.node\n var details = context.get('lockCountdown');\n //node.warn(details);\n if(details.command === 'start'){\n let lockCountdownValue = context.get('lockCountdownValue');\n let min = 0;\n if(lockCountdownValue > min){\n lockCountdownValue--\n context.set('lockCountdownValue',lockCountdownValue);\n context.t5 = setTimeout(lockCountdown, 1000);\n this.status({fill:\"green\",shape:\"dot\",text:\"lockCountdownValue trigger in: \" + context.get('lockCountdownValue') + \" s\"}); \n } else if(lockCountdownValue === min){\n let arg = 'lock'\n //lockMC(arg);\n node.send(msg)\n context.set('lockCountdown', {\"command\":'stop', \"triggered\": false});\n this.status({fill:\"red\",shape:\"dot\",text:\"machine lock trigger sent\" });\n } else {\n //node.warn('lockCountdown() send warning: this should not happen');\n //add error catching\n }\n }\n else if(details.command === 'stop'){\n let command = details.command;\n context.set('lockCountdown', {\"command\":command, \"triggered\": false});\n clearTimeout(context.t5); // timer used to trigger dlockCountdown()\n this.status({fill:\"yellow\",shape:\"square\",text:\"lockCountdownValue trigger in: \" + context.get('lockCountdownValue') + \" s\"});\n //node.warn(context.get('lockCountdown').triggered)\n }\n else if(details.command === 'clear'){\n let command = details.command;\n context.set(['lockCountdown','lockCountdownValue'], [{\"command\":command, \"triggered\": false},undefined]);\n lockCountdownTimer();\n clearTimeout(context.t5); // timer used to trigger lockCountdown()\n this.status({fill:\"blue\",shape:\"square\",text:\"lockCountdownValue trigger in: \" + context.get('lockCountdownValue') + \" s\"});\n //node.warn(context.get('lockCountdown').triggered)\n }\n}\n)\n\ncontext.set('lockCountdown',{\"command\":\"start\",\"triggered\":false})\ncontext.set('lockCountdownValue',5)\ncontext.set('testFunction',\"return \" + String(global.get('lockCountdown')))\nfunc = new Function(context.get('testFunction'))();\nfunc()\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":610,"y":2840,"wires":[["75358f110c2664d5"]]},{"id":"75358f110c2664d5","type":"debug","z":"866282f4.d0922","name":"1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":770,"y":2840,"wires":[]}]

```

I managed to get _node.status_ to "work" by replacing it with _this.status_. When triggered I'm getting

```auto
TypeError: this.status is not a function

```

but then it starts to work when it's recalled again.  
As this is for information only I can accept this behaviour (I would like to still understand what's happening)  
The problem is that I cannot get node.send() or node.,warn() to work as I'm getting:  
`ReferenceError: node is not defined`  
Being able to reuse some more complex functions will be an advantage in my opinion. The subflow route is not suitable as I would like to recall these functions inside a function node.

---

<div class="post-metadata">

**Author:** ![ralphwetzel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/ralphwetzel/32/53713_2.png) [@ralphwetzel](https://discourse.nodered.org/u/ralphwetzel)\
**Post date:** [26 April 2022 19:45 UTC](https://discourse.nodered.org/t/defining-and-reuse-a-classic-js-function/16372/16 "2022-04-26T19:45:19Z")

</div>

> [@krzydec](#):
>
> I would like to still understand what's happening

The behavior you see effects from the way `setInterval` calls the provided function - which is different from your way: From the [source](https://github.com/node-red/node-red/blob/c5efdf5ae3aa62a23ee3840d0c1db9142b213963/packages/node_modules/%40node-red/nodes/core/function/10-function.js#L264-L277) of the _function_ node:

```auto
            setInterval: function() {
                var func = arguments[0];
                var timerId;
                arguments[0] = function() {
                    try {
                        func.apply(node,arguments);
                    } catch(err) {
                        node.error(err,{});
                    }
                };
                timerId = setInterval.apply(node,arguments);
                node.outstandingIntervals.push(timerId);
                return timerId;
            },

```

You can easily spot the difference: Your launching call is

```auto
func = new Function(context.get('testFunction'))();
func();

```

whereas the following calls initiated via `setInterval` call your global function as

```auto
timerId = setInterval.apply(node,arguments);

```

defining `node` as the `this` argument to the scope. The solution is straight forward:

```auto
func.apply(node);

```

You'll still get a `"ReferenceError: node is not defined"` due to the fact that you're referencing `node` in line 17.

```auto
            node.send(msg)

```

You may fix this by replacing `node` with `this` as well:

```auto
            this.send(msg)

```

**Final remark:**  
Please open just a new topic next time if you need some support. This is preferred rather than continuing a (quite ancient) discussion closed long time ago.
