Function 节点编程
Function 节点编程
本节介绍 Node-RED 中最重要的节点——Function 节点。学习完成后,您将能够:
- 理解 Function 节点的编程模型
- 编写 JavaScript 代码处理消息
- 使用 Function 节点实现数据处理逻辑
- 掌握消息对象的操作和返回
Function Node Overview
Section titled “Function Node Overview”Function 节点允许用 JavaScript 代码实现自定义数据处理逻辑:
输入: msg (消息对象) ↓ [Function Node: JavaScript 代码] ↓输出: msg (处理后的消息对象) 或 null (丢弃消息)The Message Object (msg)
Section titled “The Message Object (msg)”// 标准消息对象结构{ _msgid: "abc123", // 消息唯一 ID topic: "sensor/temp", // 主题 (可选) payload: 25.3, // 消息载荷 (核心数据) data: {/* ... */}, // 自定义属性 (可选) headers: {/* ... */}, // HTTP 头 (HTTP 相关) req: {/* ... */}, // 请求对象 (HTTP 相关) res: {/* ... */} // 响应对象 (HTTP 相关)}Basic Function Patterns
Section titled “Basic Function Patterns”Pattern 1: 直接处理
Section titled “Pattern 1: 直接处理”// 最简单的 Function// 输入: msg.payload = 25.3// 输出: msg.payload = "Temperature: 25.3°C"
msg.payload = "Temperature: " + msg.payload + "°C";return msg;Pattern 2: 创建新对象
Section titled “Pattern 2: 创建新对象”// 创建新的消息对象// 输入: msg.payload = {temp: 25.3, hum: 68}
var result = { temperature: msg.payload.temp, humidity: msg.payload.hum, timestamp: Date.now(), status: msg.payload.temp > 30 ? "warning" : "normal"};
msg.payload = result;return msg;Pattern 3: 条件处理
Section titled “Pattern 3: 条件处理”// 条件逻辑// 输入: msg.payload = 25.3
if (msg.payload > 30) { msg.payload = { action: "cooling_on", reason: "Temperature too high" }; return msg;} else if (msg.payload < 15) { msg.payload = { action: "heating_on", reason: "Temperature too low" }; return msg;} else { return null; // 丢弃消息,不触发后续节点}Advanced Function Techniques
Section titled “Advanced Function Techniques”1. 多输出端口
Section titled “1. 多输出端口”// 配置: 设置 2 个输出端口// 输出 1: 正常数据// 输出 2: 告警数据
if (msg.payload > 30) { // 发送到输出 1 (告警) var alertMsg = { payload: "High temperature alert: " + msg.payload }; // 发送到输出 2 (日志) var logMsg = { payload: { value: msg.payload, time: Date.now() } }; return [alertMsg, logMsg];} else { // 只发送到输出 1 return [msg, null]; // null = 该输出不发送消息}2. 异步处理
Section titled “2. 异步处理”// 使用 Promise 处理异步操作return new Promise((resolve, reject) => { // 模拟异步 API 调用 setTimeout(() => { msg.payload = msg.payload * 2; resolve(msg); }, 1000);});3. 上下文访问
Section titled “3. 上下文访问”// 使用上下文存储状态var count = context.get("count") || 0;count++;context.set("count", count);
// 访问 Flow 变量var flowVar = flow.get("config") || {};flow.set("config", flowVar);
// 访问全局变量var globalVar = global.get("systemStatus") || {};global.set("systemStatus", globalVar);
msg.payload = { count: count, flowVar: flowVar, globalVar: globalVar};return msg;Common Function Examples
Section titled “Common Function Examples”示例 1: 数据格式化
Section titled “示例 1: 数据格式化”// 输入: {temp: 25.123456, hum: 68.987654}// 输出: {temperature: "25.12°C", humidity: "68.99%"}
var data = msg.payload;msg.payload = { temperature: data.temp.toFixed(2) + "°C", humidity: data.hum.toFixed(2) + "%", timestamp: new Date().toISOString()};return msg;示例 2: JSON 数据提取
Section titled “示例 2: JSON 数据提取”// 输入: 字符串 JSON// 输出: 解析后的对象
try { var jsonData = JSON.parse(msg.payload); msg.payload = { deviceId: jsonData.device, value: jsonData.value, unit: jsonData.unit }; return msg;} catch (e) { node.error("JSON parse error: " + e.message); return null;}示例 3: 数据聚合
Section titled “示例 3: 数据聚合”// 累积计算平均值var readings = context.get("readings") || [];readings.push(msg.payload);
// 只保留最近 10 个值if (readings.length > 10) { readings.shift();}context.set("readings", readings);
// 计算平均值var sum = readings.reduce((a, b) => a + b, 0);var avg = sum / readings.length;
msg.payload = { current: msg.payload, average: avg.toFixed(2), count: readings.length};return msg;Debugging Functions
Section titled “Debugging Functions”// 1. 使用 node.warn() 输出调试信息node.warn("Input value: " + msg.payload);
// 2. 使用 node.log() 记录日志node.log("Processing message from: " + msg.topic);
// 3. 使用 node.error() 输出错误try { // 处理逻辑} catch (error) { node.error("Error: " + error.message, msg);}
// 4. 结合 Debug 节点// 在 Function 节点后连接 Debug 节点// 可以直接查看返回的消息对象Function Node Properties
Section titled “Function Node Properties”| 属性 | 说明 | 示例 |
|---|---|---|
| Name | 节点名称 | ”Temperature Converter” |
| Function | JavaScript 代码 | msg.payload *= 2; return msg; |
| Outputs | 输出端口数 | 1, 2, 3… |
| On Start | 启动时执行的代码 | 初始化变量 |
| On Message | 消息处理代码 | 主要逻辑 |
Common Customer Questions
Section titled “Common Customer Questions”Q1: Function 节点支持哪些 JavaScript 语法?
Section titled “Q1: Function 节点支持哪些 JavaScript 语法?”A: 支持 ES6+ 语法(箭头函数、模板字符串、Promise、async/await 等)。运行在 Node.js 环境,可用大多数 npm 模块。
Q2: Function 节点性能如何?
Section titled “Q2: Function 节点性能如何?”A: 每个消息在 Function 节点中执行 JavaScript 代码。简单操作 < 1ms,复杂计算可能 10-100ms。建议避免繁重计算。
Q3: 如何测试 Function 节点?
Section titled “Q3: 如何测试 Function 节点?”A: 使用 Inject 节点发送测试数据,在后续连接 Debug 节点查看输出。也可以在 Function 中使用 node.warn() 输出中间结果。
✅ 推荐做法:
- 保持 Function 代码简洁(< 50 行)
- 使用 try/catch 处理错误
- 使用
return null丢弃不需要的消息 - 使用 context 存储状态数据
- 为 Function 节点设置有意义的名称
❌ 避免做法:
- 编写超过 100 行的 Function 代码
- 忽略错误处理
- 滥用全局变量
- 在 Function 中执行阻塞操作
- 不处理异步操作的错误
Summary
Section titled “Summary”- Function 节点是 Node-RED 最灵活的数据处理工具
- msg 对象是 Flow 中的核心数据载体
- 支持单输出和多输出两种模式
- context 提供局部/Flow/全局三种作用域存储
node.warn()和node.error()是主要调试手段