Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The Function node allows uses JavaScript code to be run against the messages that are passed through itand allows you to construct your logic.

The message is passed in as an object called named msg. By convention, it will have a In general, the body of the message is present in the payload property msg.payload property containing the body of the messagemsg object. The other nodes may attach their own properties to the message object.

Table of Contents

...

Function editor

The You can enter custom code entered into the Function node represents the body of the function.

The function below simply returns the message exactly as-is:

...

node and add return msg; at the end to return the whole message to be passed on to the next node in the flow.

...

Note

The function must always return a msg object.

If the function returns null, then no message is passed on and through the flow ends.The function must always return a msg objectfunction node.

Warning

Returning a number or string will result in an error.

The returned message object does not need to be the same object as was passed in; the function Though it is not advised to rewrite the whole message object, you can construct a completely new object before returning it. For example:

...

Note

Constructing a new message object will lose any message properties of the received message. This will break some flows, for example, the HTTP In/Response flow requires the msg.req and msg.res properties to be preserved end-to-end. In general, function nodes should return the message object they were passed having made any changes to its properties.

You can click on the expand button to expand the code editor to fill the screen.

...

In the expanded mode, click on the Cancel button to return to the windowed mode.

...

Use node.warn() to show warnings in the sidebar to help you debug. For example:

...

See the logging section below for more details.

Multiple Outputs

The function edit dialog allows the number of outputs to be changed. If there is more than one output, you can return an array of messages can be returned by the function to send to the outputs.

...

This makes it easy to write a function that sends the message to different outputs depending on some conditions. to the outputs using the function node. You can increase the number of outputs (also the pins of the function node) by changing the Outputs number (highlighted in the screenshot below).

...

In the Experience Designer, the function node with 3 outputs:

...

For example, this function would send anything on the topic bananaapple to the second output rather than the first:

Code Block
if (msg.topic === "bananaapple") {
   return [ null, msg ];
} else {
   return [ msg, null ];
}

The following example passes the original message as-is on the first output and a message containing the payload length is passed to the second output:

Code Block
msg.topic = "apple"
var newMsg = { 
  payload: msg.payload.length
  };
return [msg, newMsg];

Multiple Messages

...

In the following example, msg1msg2msg3 will will be sent to the first output pinmsg4msg3 will be sent to the second output pin.

Code Block
var msg1 = { payload:"first outoutput of outputpin 1" };
var msg2 = { payload:"second outoutput of outputpin 1" };
var msg3 = { payload:"third out of output 1" };
var msg4 = { payload:"only message from outputpin 2" };
return [ [ msg1, msg2, msg3 ], msg4msg3 ];

The following example splits the received payload into individual words and returns a message for each of the words.

Code Block
var outputMsgs = [];
var words = msg.payload.split(" ");
for (var w in words) {
    outputMsgs.push({payload:words[w]});
}
return [ outputMsgs ];

Sending messages asynchronously

If the function needs to perform an asynchronous action before sending a message it cannot return the message at the end of the function.

Instead, it must make use of the node.send() function, passing in the message(s) to be sent. It takes the same arrangement of messages as that can be returned, as described in the previous sections.

For example:

Code Block
doSomeAsyncWork(msg, function(result) {
    msg.payload = result;
    node.send(msg);
});
return;

The Function node will clone every message object you pass to node.send to ensure there is no unintended modification of message objects that get reused in the function.

The Function can request the runtime to not clone the first message passed to node.send by passing in false as a second argument to the function. It would do this if the message contains something that is not otherwise cloneable, or for performance reasons to minimize the overhead of sending messages:

Code Block
node.send(msg,false);

Finishing with a message

If a Function node does asynchronous work with a message, the runtime will not automatically know when it has finished handling the message.

To help it do so, the Function node should call node.done() at the appropriate time. This will allow the runtime to properly track messages through the system.

Code Block
doSomeAsyncWork(msg, function(result) {
    msg.payload = result;
    node.send(msg);
    node.done();
});
return;

Running code on start

The Function node provides a Setup tab where you can provide code that will run whenever the node is started. This can be used to set up any state the Function node requires.

For example, it can initialize values in a local context that the main Function will use:

Code Block
if (context.get("counter") === undefined) {
    context.set("counter", 0)
}

The Setup function can return a Promise if it needs to complete asynchronous work before the main Function can start processing messages. Any messages that arrive before the Setup function has completed will be queued up, and handled when it is ready.

Tidying up

If you do use asynchronous callback code in your functions then you may need to tidy up any outstanding requests, or close any connections, whenever the flow gets re-deployed. You can do this in two different ways.

Either by adding a close event handler:

Code Block
node.on('close', function() {
    // tidy up any async code here - shutdown connections and so on.
});

Logging events

Event logs

If a node needs to log something to the console, it can use one of the following functions:

Code Block
node.log("Something to happenedbe logged");
node.warn("Something happenedto youwarn shouldthe know aboutuser");
node.error("Oh no, something bad happenedRed Alert!!!");

The warn and error messages also get sent to the debug tab on the right side of the Experience Designer.

For finer-grained logging, node.trace() and node.debug() are also available. If there is no logger configured to capture those levels, they will not be seen.

Error Handling

...

If the function encounters an error that should halt the current flow, it should return nothing. To trigger a Catch node on the same tab, the function should call node.error with the original message as a second argument:

Code Block
node.error("You have hit an error", msg);

Storing data

...

It is also possible to get or set multiple values in one go:

Get

Code Block
var values = flow.get(["count", "colour", "temperature"]);
// values[0] is the 'count' value
// values[1] is the 'colour' value
// values[2] is the 'temperature' value

Set

Code Block
flow.set(["count", "colour", "temperature"], [123, "red", "1236.5"]);

In this case, any missing values are set to null.

Asynchronous context access

If the context store requires asynchronous access, the get and set functions require an extra callback parameter.

...

.

...

The first argument passed to the callback, err, is only set if an error occurred when accessing context.

The asynchronous version of the count example becomes:

...

...

context.get('count', function(err, count) {
    if (err) {
        node.error(err, msg);
    } else {
        // initialise the counter to 0 if it doesn't exist already
        count = count || 0;
        count += 1;
        // store the value back
        context.set('count',count, function(err) {
            if (err) {
                node.error(err, msg);
            } else {
                // make it part of the outgoing msg object
                msg.count = count;
                // send the message
                node.send(msg);
            }
        });
    }
});

Multiple context stores

It is possible to configure multiple context stores. For example, both a memory and file based store could be used.

The get/set context functions accept an optional parameter to identify the store to use.

Code Block
// Get value - sync
var myCount = flow.get("count", storeName);

// Get value - async
flow.get("count", storeName, function(err, myCount) { ... });

// Set value - sync
flow.set("count", 123, storeName);

// Set value - async
flow.set("count", 123, storeName, function(err) { ... })

...

Status

The function node can also provide its own status decoration in the same way that other nodes can. To set the status, call the node.status function. For example

Code Block
node.status({fill:"red",shape:"ring",text:"disconnected"});
node.status({fill:"green",shape:"dot",text:"connected"});
node.status({text:"Just text status"});

The shape property can be a ring or dot.

The fill property can be: redgreenyellowblue, or grey

If the status object is an empty object, {}, then the status entry is cleared from the node.

Code Block
node.status({});   // to clear the status

Any status updates can then also be caught by the Status node.

...

Additional modules

Additional node modules cannot be loaded directly within a Function node. Refer, What external libraries and modules are allowed in Experience Designer? for supported modules and libraries.

...