Skip to content

Commit 4a00f8e

Browse files
committed
Update function/nodejs docs for node.done changes
1 parent f87a6ae commit 4a00f8e

File tree

2 files changed

+115
-20
lines changed

2 files changed

+115
-20
lines changed

Diff for: docs/creating-nodes/node-js.md

+69-18
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,88 @@ RED.nodes.registerType("sample",SampleNode);
4545
Nodes register a listener on the `input` event to receive messages from the
4646
up-stream nodes in a flow.
4747

48+
With Node-RED 1.0, a new style of listener was introduced to allow the node
49+
to notify the runtime when it has finished handling a message. This added
50+
two new parameters to the listener function. Some care is needed to ensure
51+
the node can still be installed in Node-RED 0.x which does not use this new
52+
style of listener.
53+
4854
{% highlight javascript %}
49-
this.on('input', function(msg) {
55+
this.on('input', function(msg, send, done) {
5056
// do something with 'msg'
57+
58+
// Once finished, call 'done'.
59+
// This call is wrapped in a check that 'done' exists
60+
// so the node will work in earlier versions of Node-RED (<1.0)
61+
if (done) {
62+
done();
63+
}
5164
});
5265
{% endhighlight %}
5366

67+
#### Handling errors
68+
69+
If the node encounters an error whilst handling the message, it should pass
70+
the details of the error to the `done` function.
71+
72+
This will trigger any Catch nodes present on the same tab, allowing the user to
73+
build flows to handle the error.
74+
75+
Again, some care is needed in the case the node is installed in Node-RED 0.x which
76+
does not provide the `done` function. In that case, it should use `node.error`:
77+
78+
79+
{% highlight javascript %}
80+
let node = this;
81+
this.on('input', function(msg, send, done) {
82+
// do something with 'msg'
83+
84+
// If an error is hit, report it to the runtime
85+
if (err) {
86+
if (done) {
87+
// Node-RED 1.0 compatible
88+
done(err);
89+
} else {
90+
// Node-RED 0.x compatible
91+
node.error(err, msg);
92+
}
93+
}
94+
});
95+
{% endhighlight %}
96+
97+
5498
### Sending messages
5599

56-
Nodes can send messages to the down-stream nodes in a flow using the `send` function:
100+
If the node sits at the start of the flow and produces messages in response to
101+
external events, it should use the `send` function on the Node object:
57102

58103
{% highlight javascript %}
59104
var msg = { payload:"hi" }
60105
this.send(msg);
61106
{% endhighlight %}
62107

108+
If the node wants to send from inside the `input` event listener, in response to
109+
receiving a message, it should use the `send` function that is passed to the listener
110+
function:
111+
112+
{% highlight javascript %}
113+
let node = this;
114+
this.on('input', function(msg, send, done) {
115+
// For maximum backwards compatibility, check that send exists.
116+
// If this node is installed in Node-RED 0.x, it will need to
117+
// fallback to using `node.send`
118+
send = send || function() { node.send.apply(node,arguments) }
119+
120+
msg.payload = "hi";
121+
send(msg);
122+
123+
if (done) {
124+
done();
125+
}
126+
});
127+
{% endhighlight %}
128+
129+
63130
If `msg` is null, no message is sent.
64131

65132
If the node is sending a message in response to having received one, it should reuse
@@ -154,24 +221,8 @@ this.debug("Log something more details for debugging the node's behaviour");
154221

155222
{% endhighlight %}
156223

157-
158224
The `warn` and `error` messages also get sent to the flow editor debug tab.
159225

160-
#### Handling errors
161-
162-
If the node encounters an error that should halt the current flow, it should log
163-
the event with the `this.error` function.
164-
165-
If the error is one that a user of the node may want to handle for themselves,
166-
the function should be called with the original message (or an empty message if
167-
this is an Input node) as the second argument:
168-
169-
{% highlight javascript %}
170-
node.error("hit an error", msg);
171-
{% endhighlight %}
172-
173-
This will trigger any Catch nodes present on the same tab.
174-
175226
### Setting status
176227

177228
Whilst running, a node is able to share status information with the editor UI.

Diff for: docs/user-guide/writing-functions.md

+46-2
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,58 @@ If the function needs to perform an asynchronous action before sending a message
108108
it cannot return the message at the end of the function.
109109

110110
Instead, it must make use of the `node.send()` function, passing in the message(s)
111-
to be sent. For example:
111+
to be sent. It takes the same arrangement of messages as that can be returned, as
112+
described in the previous sections.
113+
114+
For example:
115+
116+
{% highlight javascript %}
117+
doSomeAsyncWork(msg, function(result) {
118+
msg.payload = result;
119+
node.send(msg);
120+
});
121+
return;
122+
{% endhighlight %}
123+
124+
**Since Node-RED 1.0**
125+
126+
The Function node will clone every message object you pass to `node.send` to
127+
ensure there is no unintended modification of message objects that get reused
128+
in the function. Before Node-RED 1.0, the Function node would not clone the
129+
*first* message passed to `node.send`, but would clone the rest.
130+
131+
The Function can request the runtime to *not clone* the first message passed to
132+
`node.send` by passing in `false` as a second argument to the function. It would
133+
do this is the message contains something that is not otherwise cloneable, or for
134+
performance reasons to minimise the overhead of sending messages:
135+
136+
{% highlight javascript %}
137+
node.send(msg,false);
138+
{% endhighlight %}
139+
140+
#### Finishing with a message
141+
142+
**Since Node-RED 1.0**
143+
144+
If a Function node does asynchronous work with a message, the runtime will not
145+
automatically know when it has finished handling the message.
146+
147+
To help it do so, the Function node should call `node.done()` at the appropriate
148+
time. This will allow the runtime to properly track messages through the system.
112149

113150
{% highlight javascript %}
114151
doSomeAsyncWork(msg, function(result) {
115-
node.send({payload:result});
152+
msg.payload = result;
153+
node.send(msg);
154+
node.done();
116155
});
117156
return;
118157
{% endhighlight %}
119158

159+
160+
161+
### Tidying up
162+
120163
If you do use asynchronous callback code in your functions then you may need to
121164
tidy up any outstanding requests, or close any connections, whenever the flow gets
122165
re-deployed. You can do this by adding a `close` event handler.
@@ -359,6 +402,7 @@ The following objects are available within the Function node.
359402
* `node.on(..)` : [register an event handler](#sending-messages-asynchronously)
360403
* `node.status(..)` : [update the node status](#adding-status)
361404
* `node.send(..)` : [send a message](#sending-messages-asynchronously)
405+
* `node.done(..)` : [finish with a message](#finishing-with-a-message)
362406

363407
#### `context`
364408
* `context.get(..)` : get a node-scoped context property

0 commit comments

Comments
 (0)