NodeREDGuidUKR

ДОВІДНИК З NODE-RED українською мовою

На головну Розділ
<- Основні вузли Робота з повідомленнями ->

Робота з вузлом Function

Джерело

Вузол 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];

Обробка довільної кількості виходів

Починаючи з Node-RED 1.3

node.outputCount містить кількість виходів, налаштованих для функціонального вузла.

Це дає змогу писати загальні функції, які можуть обробляти змінну кількість виходів, встановлених у діалоговому вікні редагування. Наприклад, якщо ви бажаєте випадково розподілити вхідні повідомлення між виходами, ви можете:

// Створіть масив такої ж довжини, як і кількість виходів
const messages = new Array(node.outputCount)
// Виберіть випадковий вихідний номер, на який потрібно надіслати повідомлення
const chosenOutputIndex = Math.floor(Math.random() * node.outputCount);
// Надіслати повідомлення лише на вибраний вихід
messages[chosenOutputIndex] = msg;
// Повертає масив, що містить вибраний результат
return messages;

Тепер ви можете налаштувати кількість виходів лише за допомогою діалогового вікна редагування без внесення змін до самої функції.

Відправка послідовності повідомлень

Функція може повертати на виході послідовність з декількох повідомлень, повернувши масив повідомлень у середині іншого масиву. Наступні за ним вузли отримуватимуть повідомлення один за одним у тому порядку, в якому вони були у вихідному масиві цього вузла.

У наступному прикладі, послідовність повідомлень  msg1msg2msg3  буде відправлена на перший вихід, а повідомлення 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 а з в 1.3 вона називається On Start , де ви можете надати код, який запускатиметься при кожному запуску вузла. Це можна використовувати для налаштування будь-якого стану, потрібного вузлу функцій.

Наприклад, він може ініціалізувати значення в локальному контексті, які використовуватиме основна функція:

if (context.get("counter") === undefined) {
    context.set("counter", 0)
}

image-20230311144409926

Обробка Setup функції настройки може повернути Promise, якщо їй потрібно виконати асинхронну роботу до того, як основна функція може розпочати обробку повідомлень. Будь-які повідомлення, які надійдуть до завершення функції настройки, будуть вставлені в чергу і обробляться, коли вони будуть готові.

Аналогічно є вкладка On Stop де виконується код перед повторним розгортанням Node-RED.

Встановлення модулів та інші налаштування (Setup)

На вкладці “Setup” в вузлі “Function” в Node-RED налаштовуються залежності Node.js (пакети), які потрібні для виконання коду, написаного в цьому вузлі. В цьому розділі можна встановлювати, оновлювати або видаляти модулі, а також керувати версіями та залежностями за допомогою файлу package.json.

Крім того, на вкладці “Setup” можна налаштувати середовище виконання коду, включаючи змінні оточення, доступні для використання в коді. Наприклад, ви можете встановити змінні середоивща для підключення до бази даних або інших зовнішніх служб.

Також на вкладці “Setup” можна налаштувати параметри виконання коду, наприклад, час очікування або ліміт пам’яті, які можуть бути корисні для оптимізації виконання коду в вузлі “Function”.

У вузлі Function на вкладці “Setup” міститься розділ “Modules”. Цей розділ дозволяє встановлювати залежності Node.js (пакети) для використання в коді JavaScript, який ви пишете в цьому вузлі. Наприклад, якщо ви хочете використовувати сторонні бібліотеки або модулі у своєму коді JavaScript, ви можете встановити їх через цей розділ “Modules”. Це може бути корисно, коли ви хочете використовувати більш складні або спеціалізовані функції, які не є доступними за замовчуванням у вузлі Function. У розділі “Modules” ви можете встановлювати нові модулі, оновлювати вже встановлені модулі або видаляти модулі, які більше не потрібні. Крім того, ви можете використовувати спеціальний файл package.json для керування залежностями та їх версіями. Це дозволяє зробити ваш код більш структурованим та керованим.

Прибирання

Якщо ви використовуєте асинхронний код зворотного виклику у своїх функціях, коли потік повторно розгортається, вам знадобиться прибирати будь-які непотрібні запити або закривати будь-які з'єднання. Ви можете зробити це, додавши обробник подій close

node.on('close', function() {
    // tidy up any async code here - shutdown connections and so on.
});

Починаючи з Node-RED 1.1.0 цей код можна вписати в налаштуваннях закладки Close вузла Функції абоOn Stop у новіших функціях.

Ведення журналу подій

Якщо вузол повинен записувати щось в консоль, він може використовувати одну з наступних функцій:

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 є три заздалегідь визначені змінні, які можна використовувати для доступу до контексту:

Зауважте. Ці заздалегідь означені змінні є особливостями вузла 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

Using the functionExternalModules option

Since Node-RED 1.3.0

Якщо встановити functionExternalModules на true у вашому файлі settings.js, діалогове вікно редагування вузла Function надасть список, де ви можете додати додаткові модулі, які повинні бути доступні для вузла. Ви також вказуєте змінну, яка використовуватиметься для посилання на модуль у коді вузла.

img

Модулі автоматично встановлюються в ~/.node-red/externalModules/, коли вузол розгортається.

Довідник API

Наступні об'єкти доступні в межах вузла Function.

node

context

flow

global

RED

env

Вузол Function також робить доступними наступні модулі та функції:

Вузол Function автоматично очищує будь-які прострочені тайм-аути або таймери інтервалів, коли він зупиняється або повторно розгортається.

Робота з повідомленнями ->