Function节点允许针对传递通过它的消息运行JavaScript代码。
消息以名为msg
的对象形式传入。按照惯例,它将包含一个msg.payload
属性,其中存储着消息的主体内容。
其他节点可能会将自己的属性附加到消息中,这些属性应在各自的文档中进行说明。
在Function节点中输入的代码代表该函数的主体部分。 最简单的函数实现就是原样返回消息:
return msg;
如果函数返回null
,则不会传递任何消息,流程结束。
函数必须始终返回一个msg对象。返回数字或字符串将导致错误。
返回的消息对象不需要与传入的对象相同;该函数可以在返回之前构造一个全新的对象。例如:
var newMsg = { payload: msg.payload.length };
return newMsg;
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.使用node.warn()在侧边栏显示警告信息以帮助调试。例如:
node.warn("my var xyz = " + xyz);
更多详情请参阅下方的日志记录部分。
函数编辑对话框允许更改输出数量。如果有多个输出,函数可以返回一个消息数组发送到各个输出端口。
这样可以轻松编写一个根据某些条件将消息发送到不同输出的函数。例如,以下函数会将主题为banana
的任何内容发送到第二个输出而非第一个:
if (msg.topic === "banana") {
return [ null, msg ];
} else {
return [ msg, null ];
}
以下示例将原始消息原样传递到第一个输出,并将包含负载长度的消息传递到第二个输出:
var newMsg = { payload: msg.payload.length };
return [msg, newMsg];
自 Node-RED 1.3 起
node.outputCount
包含为函数节点配置的输出数量。
这样就可以编写能够处理从编辑对话框中设置的变量数量输出的通用函数。
例如,如果您希望将传入消息随机分配到多个输出之间,您可以:
// Create an array same length as there are outputs
const messages = new Array(node.outputCount)
// Choose random output number to send the message to
const chosenOutputIndex = Math.floor(Math.random() * node.outputCount);
// Send the message only to chosen output
messages[chosenOutputIndex] = msg;
// Return the array containing chosen output
return messages;
现在您可以直接通过编辑对话框配置输出数量,无需修改函数本身。
一个函数可以通过返回消息数组的方式在单个输出上返回多条消息。当某个输出返回多条消息时,后续节点将按照消息被返回的顺序逐一接收这些消息。
在以下示例中,msg1
、msg2
、msg3
将被发送到第一个输出端口。
msg4
将被发送到第二个输出端口。
var msg1 = { payload:"first out of output 1" };
var msg2 = { payload:"second out of output 1" };
var msg3 = { payload:"third out of output 1" };
var msg4 = { payload:"only message from output 2" };
return [ [ msg1, msg2, msg3 ], msg4 ];
以下示例将接收到的有效载荷拆分为单个单词,并为每个单词返回一条消息。
var outputMsgs = [];
var words = msg.payload.split(" ");
for (var w in words) {
outputMsgs.push({payload:words[w]});
}
return [ outputMsgs ];
如果函数在发送消息前需要执行异步操作,则无法在函数结束时返回消息。
相反,它必须使用node.send()
函数,传入要发送的消息。它接受与可以返回的消息相同的排列方式,如前面章节所述。
例如:
doSomeAsyncWork(msg, function(result) {
msg.payload = result;
node.send(msg);
});
return;
Function节点会克隆您传递给node.send
的每个消息对象,以确保在函数中重复使用的消息对象不会被意外修改。在Node-RED 1.0之前,Function节点不会克隆传递给node.send
的第一个消息,但会克隆其余消息。
该函数可以通过将false
作为第二个参数传入,要求运行时不要克隆传递给node.send
的第一条消息。当消息包含不可克隆的内容时,或者出于性能考虑需要最小化消息发送开销时,可以采用这种方式:
node.send(msg,false);
自 Node-RED 1.0 起
如果Function节点对消息进行异步处理,运行时将无法自动知晓消息处理何时完成。
为了帮助实现这一点,Function节点应在适当的时候调用node.done()
。这将允许运行时系统正确地跟踪消息流转。
doSomeAsyncWork(msg, function(result) {
msg.payload = result;
node.send(msg);
node.done();
});
return;
自 Node-RED 1.1.0 起
在1.1.0版本中,Function节点提供了一个On Start
标签页(1.3.0之前标记为Setup
),您可以在其中编写节点启动时运行的代码。这可用于设置Function节点所需的任何状态。
例如,它可以在本地上下文中初始化主函数将使用的值:
if (context.get("counter") === undefined) {
context.set("counter", 0)
}
如果On Start函数需要完成异步工作后才能开始处理消息,它可以返回一个Promise。在On Start函数完成之前到达的任何消息都将被排队,并在准备就绪时处理。
如果在函数中使用异步回调代码,那么每当流程被重新部署时,可能需要清理任何未完成的请求或关闭任何连接。您可以通过两种不同的方式实现这一点。
可以通过添加一个close
事件处理程序来实现:
node.on('close', function() {
// tidy up any async code here - shutdown connections and so on.
});
或者,从Node-RED 1.1.0版本开始,您可以在节点的编辑对话框中的On Stop
选项卡(之前标记为Close
)中添加代码。
如果节点需要向控制台输出日志信息,可以使用以下函数之一:
node.log("Something happened");
node.warn("Something happened you should know about");
node.error("Oh no, something bad happened");
控制台输出的显示位置取决于您的操作系统以及如何启动Node-RED。
如果通过命令行启动 - 日志将显示在该控制台中。如果作为系统服务运行,则可能出现在系统日志里。如果在PM2等应用程序下运行,它将有自己的日志显示方式。在树莓派上,安装脚本添加了node-red-log
命令来显示日志。
warn
和 error
消息也会发送到流程编辑器右侧的调试选项卡。
如需更精细的日志记录,还可使用node.trace()
和node.debug()
。
如果未配置记录器来捕获这些级别,则不会显示这些日志。
如果函数遇到需要中止当前流程的错误,它应该不返回任何内容。要在同一标签页触发Catch节点,函数应调用node.error
并将原始消息作为第二个参数:
node.error("hit an error", msg);
除了msg
对象外,该函数还可以在上下文存储中保存数据。
有关Node-RED中上下文的更多信息,请参阅此处。
在Function节点中,有三个预定义变量可用于访问上下文:
context
- 节点的本地上下文flow
- 流程作用域上下文global
- 全局作用域上下文以下示例使用flow
上下文,但同样适用于context
和global
。
访问上下文有两种模式:同步或异步。 内置的上下文存储提供这两种模式。某些存储可能仅支持异步访问,如果尝试同步访问则会抛出错误。
从上下文中获取一个值:
var myCount = flow.get("count");
设置一个值:
flow.set("count", 123);
以下示例记录了该函数已运行的次数:
// initialise the counter to 0 if it doesn't exist already
var count = context.get('count')||0;
count += 1;
// store the value back
context.set('count',count);
// make it part of the outgoing msg object
msg.count = count;
return msg;
自Node-RED 0.19版本起,还可以一次性获取或设置多个值:
// Node-RED 0.19 or later
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
// Node-RED 0.19 or later
flow.set(["count", "colour", "temperature"], [123, "red", "12.5"]);
在这种情况下,任何缺失值都会被设为null
。
如果上下文存储需要异步访问,get
和set
函数需要额外的回调参数。
// Get single value
flow.get("count", function(err, myCount) { ... });
// Get multiple values
flow.get(["count", "colour"], function(err, count, colour) { ... })
// Set single value
flow.set("count", 123, function(err) { ... })
// Set multiple values
flow.set(["count", "colour"], [123, "red"], function(err) { ... })
传递给回调函数的第一个参数err
,仅在访问上下文发生错误时被设置。
计数示例的异步版本变为:
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);
}
});
}
});
从0.19版本开始,可以配置多个上下文存储。例如,可以同时使用基于memory
和file
的存储。
get
/set
上下文函数接受一个可选参数来标识要使用的存储。
// 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) { ... })
Node-RED启动时,全局上下文可以预先填充对象。这需要在主settings.js文件中的functionGlobalContext
属性下进行定义。
这可用于在Function节点中加载额外模块。
功能节点也可以像其他节点一样提供自己的状态装饰。要设置状态,可以调用node.status
函数。例如
node.status({fill:"red",shape:"ring",text:"disconnected"});
node.status({fill:"green",shape:"dot",text:"connected"});
node.status({text:"Just text status"});
node.status({}); // to clear the status
有关可接受参数的详细信息,请参阅 Node Status documentation
任何状态更新也可以通过状态节点捕获。
functionGlobalContext
选项无法直接在Function节点中加载额外的节点模块。必须在您的settings.js文件中加载,并添加到functionGlobalContext
属性中。
例如,通过将以下内容添加到您的settings.js文件中,内置的os
模块就可以对所有函数可用。
functionGlobalContext: {
osModule:require('os')
}
此时,该模块可以在函数中通过 global.get('osModule')
来引用。
从您的设置文件中加载的模块必须安装在设置文件所在的同一目录下。对于大多数用户来说,这将是默认的用户目录 - ~/.node-red
:
cd ~/.node-red
npm install name_of_3rd_party_module
functionExternalModules
选项自 Node-RED 1.3.0 起
通过在settings.js文件中将functionExternalModules
设置为true
,Function节点的编辑对话框将提供一个列表,您可以在其中添加该节点可用的额外模块。您还需要指定在节点代码中引用该模块时使用的变量。
模块会在节点部署时自动安装到~/.node-red/node_modules/
目录下。
自 Node-RED 3.1.0 起
可以在设置选项卡中为函数节点设置超时时间。该值以秒为单位,表示运行时允许函数节点执行多长时间后触发错误。如果设置为0(默认值),则不应用超时限制。
以下对象在Function节点中可用。
node
node.id
: Function节点的ID - 0.19版本新增node.name
: Function节点的名称 - 0.19版本新增node.outputCount
: 为Function节点设置的输出数量 - 1.3版本新增node.log(..)
: 记录一条消息node.warn(..)
: 记录一条警告信息node.error(..)
: 记录错误信息node.debug(..)
: 记录调试信息node.trace(..)
: 记录一条跟踪消息node.on(..)
: 注册一个事件处理程序node.status(..)
: 更新节点状态node.send(..)
: 发送消息node.done(..)
: 完成并附带一条消息context
context.get(..)
: 获取节点作用域上下文属性context.set(..)
: 设置节点作用域的上下文属性context.keys(..)
: 返回节点作用域内所有上下文属性键的列表context.flow
: 同 flow
context.global
: 等同于 global
flow
flow.get(..)
: 获取流程范围内的上下文属性flow.set(..)
: 设置一个流程范围内的上下文属性flow.keys(..)
: 返回所有流作用域上下文属性键的列表global
global.get(..)
: 获取全局作用域的上下文属性global.set(..)
: 设置一个全局作用域的上下文属性global.keys(..)
: 返回所有全局作用域上下文属性键的列表RED
RED.util.cloneMessage(..)
: 安全克隆消息对象以便重复使用env
env.get(..)
: 获取环境变量Function节点还提供以下模块和函数:
Buffer
- Node.js 的 Buffer
模块console
- Node.js的console
模块(推荐使用node.log
方法进行日志记录)util
- Node.js的util
模块setTimeout/clearTimeout
- JavaScript超时函数。setInterval/clearInterval
- JavaScript的定时器函数。注意:每当函数节点停止或重新部署时,它会自动清除所有未完成的超时或间隔计时器。
Node-RED: 面向事件驱动应用的低代码编程平台。
版权所有 OpenJS基金会 及 Node-RED 贡献者。保留所有权利。OpenJS基金会 拥有注册商标并使用商标。有关 OpenJS基金会 的商标列表,请参阅我们的 商标政策 和 商标列表。未在 OpenJS基金会商标列表 中标注的商标™或注册®商标归其各自持有人所有。使用这些商标并不意味着与它们有任何关联或获得其认可。
The OpenJS Foundation | 使用条款 | 隐私政策 | OpenJS基金会章程 | 商标政策 | 商标列表 | Cookie政策