На головну | Розділ |
---|---|
<- Основні вузли | Робота з повідомленнями -> |
Вузол Function дозволяє виконувати код JavaScript для обробки повідомлень, що передаються через нього. Повідомлення передається у вигляді об'єкта з назвою msg
. За замовченням він має властивість msg.payload
що містить тіло повідомлення. Інші вузли можуть додавати до повідомлення власні властивості, які повинні бути описані у документації.
Код, введений у вузол Function -- це тіло функції. Найпростіша функція просто повертає повідомлення:
return msg;
Якщо функція повертає null
, тоді жодне повідомлення від вузла функції не передається далі, тобто потік на ньому закінчується. Повернений функцією об'єкт-повідомлення не обов'язково повинен бути таким самим типом об'єкту, який був переданий їй. Тобто функція може побудувати зовсім новий об'єкт, перш ніж повертати його. Наприклад:
var newMsg = { payload: msg.payload.length };
return newMsg;
Зауважте. Створюючи новий об'єкт msg
, повідомлення втрачає будь-які властивості того повідомлення, що було отримане на вході. Це призведе до руйнування деяких потоків, наприклад потік HTTP In/Response
вимагає щоб властивості msg.req
і msg.res
були збережені від кінця до кінця. Загалом, вузли Function мали б повертати об'єкт-повідомлення, вносячи будь-які зміни до його властивостей.
Діалог редагування Function дозволяє змінити кількість виходів. Якщо є більше одного виходу, для відправки на ці виходи повідомлень треба використати масив. Це полегшує написання функції, яка відправляє повідомлення на різні виходи в залежності від певного стану. Наприклад, ця функція буде надсилати що-небудь на тему (topic) banana
до другого виходу, а не до першого
if (msg.topic === "banana") {
return [ null, msg ];
} else {
return [ msg, null ];
}
У наступному прикладі, оригінальне вхідне повідомлення передається на перший вихід, а на другий вихід передається повідомлення, яке містить довжину рядку payload:
var newMsg = { payload: msg.payload.length };
return [msg, newMsg];
Функція може повертати на виході послідовність з декількох повідомлень, повернувши масив повідомлень у середині іншого масиву. Наступні за ним вузли отримуватимуть повідомлення один за одним у тому порядку, в якому вони були у вихідному масиві цього вузла.
У наступному прикладі, послідовність повідомлень 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 ];
У наступному прикладі отримане корисне навантаження (payload) розбивається на окремі слова, і повертається повідомлення, що вміщує кожне слово.
var outputMsgs = [];
var words = msg.payload.split(" ");
for (var w in words) {
outputMsgs.push({payload:words[w]});
}
return [ outputMsgs ];
Якщо функція повинна виконувати асинхронну дію (що не відразу повертає результат а потребує функцію зворотного виклику) що приймає участь у формуванні повідомлення, вона не може повернути повідомлення по завершенню обробки Function. Замість цього повинна використовуватися функція передачі повідомлень node.send()
. Наприклад:
doSomeAsyncWork(msg, function(result) {
msg.payload = result;
node.send(msg);
});
return;
Вузол функції буде клонувати кожен об’єкт повідомлення, який ви передаєте в node.send
, щоб уникнути ненавмисної модифікації об’єктів повідомлень, які повторно використовуються у функції. До версії Node-RED 1.0 вузол функцій не клонував перше повідомлення, передане в node.send
, а клонував тільки решту.
Функція може запитувати середовище виконання не клонувати перше повідомлення, передане в node.send
, передаючи в якості другого аргументу функції send
значення false
. Зрозуміло, що це повідомлення містить щось, що не може бути клоноване інакше, або з міркувань продуктивності, щоб мінімізувати накладні витрати на надсилання повідомлень:
node.send(msg,false);
Якщо вузол Function виконує асинхронну роботу з повідомленням, середовище виконання не буде автоматично знати, коли воно закінчило обробляти повідомлення.
Щоб допомогти це зробити, вузол Function повинен викликати node.done()
у відповідний час. Це дозволить виконувати належним чином відстеження повідомлень через систему.
doSomeAsyncWork(msg, function(result) {
msg.payload = result;
node.send(msg);
node.done();
});
return;
Починаючи версії 1.1.0, вузол Function забезпечує вкладку Setup
, де ви можете надати код, який запускатиметься при кожному запуску вузла. Це можна використовувати для налаштування будь-якого стану, потрібного вузлу функцій.
Наприклад, він може ініціалізувати значення в локальному контексті, які використовуватиме основна функція:
if (context.get("counter") === undefined) {
context.set("counter", 0)
}
Обробка Setup функції настройки може повернути Promise, якщо їй потрібно виконати асинхронну роботу до того, як основна функція може розпочати обробку повідомлень. Будь-які повідомлення, які надійдуть до завершення функції настройки, будуть вставлені в чергу і обробляться, коли вони будуть готові.
Якщо ви використовуєте асинхронний код зворотного виклику у своїх функціях, коли потік повторно розгортається, вам знадобиться прибирати будь-які непотрібні запити або закривати будь-які з'єднання. Ви можете зробити це, додавши обробник подій close
node.on('close', function() {
// tidy up any async code here - shutdown connections and so on.
});
Починаючи з Node-RED 1.1.0 цей код можна вписати в налаштуваннях закладки Close
вузла Функції.
Якщо вузол повинен записувати щось в консоль, він може використовувати одну з наступних функцій:
node.log("Something happened");
node.warn("Something happened you should know about");
node.error("Oh no, something bad happened");
Повідомлення warn
і error
також надсилаються на вкладку налагодження редактора потоку. Для більш тонкорівневих подій також доступні node.trace()
і node.debug()
. Якщо для цих рівнів не налаштоване ведення журналу, вони відображатися не будуть.
Якщо функція виявляє помилку, вона припиняє поточний потік і нічого не повертає. Щоб запустити вузол Catch
для обробки помилок на тій самій вкладці, функція повинна викликати node.error
з оригінальним повідомленням в якості другого аргументу:
node.error("hit an error", msg);
Крім об'єкту msg
функція також може зберігати дані в контекстних сховищах. У вузлі Function є три заздалегідь визначені змінні, які можна використовувати для доступу до контексту:
-
context
- локальний контекст вузла -
flow
- контекст потоку -
global
- глобальний контекст
Зауважте. Ці заздалегідь означені змінні є особливостями вузла Function. Якщо ви створюєте спеціальний вузол, прочитайте Creating Nodes guide для ознайомлення з тим, як отримати доступ до контексту.
Наступні приклади використовують контекст потоку flow
, але аналогічно цей приклад застосовний і до context
, і до global
.
Існує два режими доступу до контексту: синхронний та асинхронний. Синхронний доступ означає, що виклик для отримання даних з сховища негайно повертає значення. Асинхронний доступ означає, що функція виклику для отримання даних також повинен містити функцію зворотного виклику, яка викликається після того, як значення стало доступним. Вбудовані сховища memory і file обидва пропонують синхронний доступ. Це означає, що існуючі (попередні до версії 0.19) потоки можуть використовувати ці сховища без будь-яких змін.
Щоб отримати значення з контексту використовується метод get
:
var myCount = flow.get("count");
Щоб встановити значення в контекст, використовується метод set
:
flow.set("count", 123);
У наведеному нижче прикладі зберігається лічильник кількості викликів функції:
// ініціалізація змінної лічильника ‘count’ в 0, якщо її немає в контексті
// вузла
var count = context.get('count')||0;
count += 1;
// збереження значення store в контексті вузла під іменем ‘count’
context.set('count',count);
// зробити це частиною вихідного об’єкту msg
msg.count = count;
return msg;
Node-RED може отримати або встановити декілька значень за один раз:
// Node-RED 0.19 або пізніше
var values = flow.get(["count", "colour", "temperature"]);
// values[0] це значення 'count'
// values[1] це значення 'colour'
// values[2] це значення 'temperature'
// Node-RED 0.19 або пізніше
flow.set(["count", "colour", "temperature"], [123, "red", "12.5"]);
У цьому випадку для будь-яких відсутніх значень буде встановлено значення null.
Якщо для контекстного сховища потрібен асинхронний доступ, то функції get
та set
вимагають додаткового параметра функції зворотного виклику.
// отримати одне значення
flow.get("count", function(err, myCount) { ... });
// отримати кілька значень
flow.get(["count", "colour"], function(err, count, colour) { ... })
// встановити одне значення
flow.set("count", 123, function(err) { ... })
// встановити кілька значень
flow.set(["count", "colour", [123, "red"], function(err) { ... })
Перший аргумент у функції зворотного виклику, err
, встановлюється лише тоді, коли при доступі до контексту виникла помилка.
Приклад асинхронної версії наведеної вище функції підрахунку кількості викликів функції:
context.get('count', function(err, count) {
if (err) {
node.error(err, msg);
} else {
// ініціалізація змінної лічильника ‘count’ в 0, якщо її
// немає в контексті вузла
count = count || 0;
count += 1;
// збереження значення store в контексті вузла під іменем ‘count’
context.set('count',count, function(err) {
if (err) {
node.error(err, msg);
} else {
// зробити це частиною вихідного об’єкту msg
msg.count = count;
// відправити повідомлення
node.send(msg);
}
});
}
});
З версії 0.19 можна налаштувати кілька контекстних сховищ. Наприклад, можуть бути використані два типа сховищ, що базуються на memory
і file
.
Функції роботи з контекстом get
/set
приймають необов'язковий параметр (у прикладі це storeName
) для ідентифікації сховища для використання.
// отримати значення синхронно - sync
var myCount = flow.get("count", storeName);
// отримати значення асинхронно - async
flow.get("count", storeName, function(err, myCount) { ... });
// встановити значення синхронно - sync
flow.set("count", 123, storeName);
// встановити значення асинхронно - async
flow.set("count", 123, storeName, function(err) { ... })
Коли Node-RED запускаються глобальний контекст може бути попередньо заповнений об'єктами. Це означено в основному файлі settings.js властивістю functionGlobalContext
.
Це може бути використано для Завантаження додаткових модулів в межах вузла Function.
Вузол 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({}); // для очищення статусу
Тоді будь-які оновлення статусу можуть також потрапляти до вузла Status.
У вузлі 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
Наступні об'єкти доступні в межах вузла Function.
node
-
node.id : ідентифікатор вузла Function - додано в 0,19
-
node.name : назва функціонального вузла - додано в 0,19
-
node.log(..) : запис повідомлення
-
node.warn(..) : log a warning message
-
node.error(..) : log an error message
-
node.debug(..) : log a debug message
-
node.trace(..) : log a trace message
-
node.on(..) : register an event handler
-
node.status(..) : update the node status
-
node.send(..) : send a message
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
get(..)
: get an environment variable
Вузол Function також робить доступними наступні модулі та функції:
-
Buffer
- модуль Node.jsBuffer
-
console
- модуль Node.jsconsole
(node.log є наперед визначеним методом ведення журналу) -
util
- модуль Node.jsutil
-
setTimeout/clearTimeout
- функція тайм-ауту javascript. -
setInterval/clearInterval
- функції інтервалу javascript.
Вузол Function автоматично очищує будь-які прострочені тайм-аути або таймери інтервалів, коли він зупиняється або повторно розгортається.