函数节点允许对流经它的消息运行 JavaScript 代码。
消息以一个名为 msg
的对象传入。按照惯例,它将具有一个包含消息正文的 msg.payload
属性。
其他节点可能会将自己的属性附加到消息中,这些属性应在其文档中进行说明。
在函数节点中输入的代码代表函数的 主体。最简单的函数只是按原样返回消息
return msg;
如果函数返回 null
,则不会传递任何消息,并且流程结束。
函数必须始终返回一个 msg 对象。返回数字或字符串将导致错误。
返回的消息对象不必与传入的对象相同;函数可以在返回之前构造一个全新的对象。例如
var newMsg = { payload: msg.payload.length };
return newMsg;
msg.req
和 msg.res
属性端到端保留。通常,函数节点 应该 返回它们接收到的消息对象,并在其属性上进行任何更改。使用 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;
函数节点将克隆您传递给 node.send
的每个消息对象,以确保函数中重复使用的消息对象不会被意外修改。在 Node-RED 1.0 之前,函数节点不会克隆传递给 node.send
的 第一条 消息,但会克隆其余消息。
函数可以通过将 false
作为第二个参数传递给函数,请求运行时 不克隆 传递给 node.send
的第一条消息。如果消息包含无法克隆的内容,或者出于性能原因以最小化发送消息的开销,则会这样做
node.send(msg,false);
自 Node-RED 1.0 起
如果函数节点使用消息执行异步工作,则运行时不会自动知道何时完成处理消息。
为了帮助它,函数节点应该在适当的时候调用 node.done()
。这将允许运行时正确地跟踪系统中的消息。
doSomeAsyncWork(msg, function(result) {
msg.payload = result;
node.send(msg);
node.done();
});
return;
自 Node-RED 1.1.0 起
随着 1.1.0 版本的发布,函数节点提供了一个 启动时
选项卡(1.3.0 之前标记为 设置
),您可以在其中提供节点启动时运行的代码。这可以用于设置函数节点所需的任何状态。
例如,它可以在主函数将使用的本地上下文中初始化值
if (context.get("counter") === undefined) {
context.set("counter", 0)
}
如果启动函数需要完成异步工作才能使主函数开始处理消息,则它可以返回一个 Promise。在启动函数完成之前到达的任何消息都将排队,并在准备好时进行处理。
如果您在函数中使用异步回调代码,那么每当流程重新部署时,您可能需要清理任何未完成的请求,或关闭任何连接。您可以通过两种不同的方式进行。
通过添加 close
事件处理程序
node.on('close', function() {
// tidy up any async code here - shutdown connections and so on.
});
或者,自 Node-RED 1.1.0 起,您可以将代码添加到节点编辑对话框中的 停止时
选项卡(以前标记为 关闭
)。
如果节点需要将某些内容记录到控制台,它可以使用以下函数之一
node.log("Something happened");
node.warn("Something happened you should know about");
node.error("Oh no, something bad happened");
控制台输出出现的位置将取决于您的操作系统以及您如何启动 Node-RED。如果您使用命令行启动 - 那就是日志将出现的控制台。如果您作为系统服务运行,则它可能会出现在系统日志中。如果您在 PM2 等应用程序下运行,它将有自己的显示日志的方式。在 Raspberry Pi 上,安装脚本添加了一个 node-red-log
命令,它将显示日志。
warn
和 error
消息也会发送到流程编辑器右侧的调试选项卡。
为了更细粒度的日志记录,node.trace()
和 node.debug()
也可用。如果没有配置日志记录器来捕获这些级别,则它们将不可见。
如果函数遇到应停止当前流程的错误,则它不应返回任何内容。要在同一选项卡上触发 Catch 节点,函数应调用 node.error
并将原始消息作为第二个参数
node.error("hit an error", msg);
除了 msg
对象之外,函数还可以将数据存储在上下文存储中。
有关 Node-RED 中上下文的更多信息,请参见此处。
在函数节点中有三个预定义变量可用于访问上下文
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
属性下定义。
这可以用于在函数节点中加载额外的模块。
函数节点也可以像其他节点一样提供自己的状态装饰。要设置状态,请调用 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
有关接受参数的详细信息,请参阅节点状态文档
任何状态更新也可以被状态节点捕获。
functionGlobalContext
选项不能直接在函数节点中加载额外的节点模块。它们必须在您的 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
,函数节点的编辑对话框将提供一个列表,您可以在其中添加应可用于节点的额外模块。您还可以指定将用于在节点代码中引用模块的变量。
模块在部署节点时会自动安装在 ~/.node-red/node_modules/
下。
自 Node-RED 3.1.0 起
可以在“设置”选项卡上为函数节点设置超时。此值以秒为单位,是运行时允许函数节点运行的时间,超过该时间将引发错误。如果设置为 0(默认值),则不应用超时。
以下对象在函数节点中可用。
node
node.id
:函数节点的 id - 0.19 中添加node.name
:函数节点的名称 - 0.19 中添加node.outputCount
:为函数节点设置的输出数量 - 1.3 中添加node.log(..)
:记录消息node.warn(..)
:记录警告消息node.error(..)
:记录错误消息node.debug(..)
:记录调试消息node.trace(..)
:记录跟踪消息node.on(..)
:注册事件处理程序node.status(..)
:更新节点状态node.send(..)
:发送消息node.done(..)
:完成消息上下文
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(..)
:获取环境变量函数节点还提供以下模块和函数
Buffer
- Node.js Buffer
模块console
- Node.js console
模块(node.log
是首选的日志记录方法)util
- Node.js util
模块setTimeout/clearTimeout
- javascript 超时函数。setInterval/clearInterval
- javascript 间隔函数。注意:函数节点在停止或重新部署时会自动清除任何未完成的超时或间隔计时器。
版权所有 OpenJS Foundation 和 Node-RED 贡献者。保留所有权利。OpenJS Foundation 已注册商标并使用商标。有关 OpenJS Foundation 商标列表,请参阅我们的商标政策和商标列表。未在OpenJS Foundation 商标列表中指明的商标和徽标是其各自持有人的商标™或注册®商标。使用它们并不意味着与它们有任何关联或认可。
OpenJS Foundation | 使用条款 | 隐私政策 | OpenJS Foundation 章程 | 商标政策 | 商标列表 | Cookie 政策