Node-RED编写Functions
Function节点允许对传入的消息使用JavaScript代码进行编程。
在Function节点中的变量使用、运算符、if 分支语句、switch语句等用法与JavaScript基本一致,可以参考JavaScript 教程 | 菜鸟教程。需要具备一定的JS编程能力。
传入的消息作为一个名为 msg
的对象。按照惯例是这样的具有包含消息主体的 msg.payload
属性。
其他节点可以将自己的属性附加到消息上,它们也应该这样做在他们的文档中有描述。
编写Function
输入到Function节点中的代码表示函数体。最简单的函数只是按原样返回消息:
return msg;
如果函数返回 null
,则不传递任何消息,Flow流结束。
函数必须总是返回一个msg对象。返回一个数字或字符串将导致错误。
返回的消息对象不需要与传入的对象相同;函数可以在返回对象之前构造一个全新的对象。为 例子:
var newMsg = { payload: msg.payload.length }; return newMsg;
注意:构造一个新的消息对象将丢失接收到的消息的任何消息属性。这将打破一些流,例如,HTTP In/Response流需要
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;
Function节点将把传递给 node.send
的每个消息对象克隆到 确保重用的消息对象没有意外修改 在函数中。在node – red 1.0之前,Function节点不会克隆 第一个消息传递给 node.send
,但是会克隆其余的。
函数可以请求运行时不克隆传递给的第一条消息 node.send
通过传递 false
作为函数的第二个参数来实现。它将 如果消息包含不可克隆的内容,则执行此操作 最小化发送消息开销的性能原因:
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节点所需的任何状态。
例如,它可以初始化main函数的局部上下文中的值 将使用:
if (context.get("counter") === undefined) { context.set("counter", 0) }
如果需要完成异步工作,On Start函数可以返回一个Promise 在main函数开始处理消息之前。任何到达的消息 在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这样的应用下运行,它会有自己的方式来显示日志。在Pi上,安装脚本添加了一个 node-red-log
命令,该命令将显示日志。
warn
和 error
消息也被发送到流编辑器右侧的debug选项卡。
对于更细粒度的日志记录,还可以使用 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
只有在出现错误时才会设置 访问上下文时发生。
count示例的异步版本变成:
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) { ... })
Global上下文
Global上下文可以在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
有关可接受参数的详细信息,请参见 节点状态文档
任何状态更新都可以被status节点捕获。
加载附加模块
使用 functionGlobalContext
选项
不能在Function节点中直接加载其他节点模块。他们必须 加载到settings.js文件中,并添加到 functionGlobalContext
财产。
例如,内置的 os
模块可以通过以下方式对所有函数可用 将以下内容添加到settings.js文件中。
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的编辑对话框将提供一个列表,您可以在其中添加其他模块 对于节点来说应该是可用的。您还指定将执行该操作的变量 用于引用节点代码中的模块。
模块在节点部署时自动安装在 ~/.node-red/externalModules/
目录下。
处理超时
从Node-RED 3.1.0开始
可以在Setup选项卡上为功能节点设置超时。这个值, 以秒为单位表示运行时允许Function节点运行的时间 引发错误。如果设置为0,则默认不应用超时。
API参考
以下对象在Function节点中可用。
node
node.id
: Function节点的id -在0.19中添加node.name
: Function节点的名称-在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
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(..)
:获取环境变量 //双击flow标签页,在环境变量标签页内添加。注意没有set和keys
其他模块和功能
“功能”节点还提供以下模块和功能:
Buffer
– Node.jsBuffer
模块console
– Node.jsconsole
模块(node.log
是首选的日志记录方法)util
– Node.jsutil
模块setTimeout/clearTimeout
– javascript超时函数。setInterval/clearInterval
– javascript的interval函数。
注意:功能节点将自动清除所有未完成的超时或 停止或重新部署的间隔计时器。
1 条回复
[…] 关于使用Function节点的完整指南可以在这里找到。 […]