|
|
(не показано 5 промежуточных версий 3 участников) |
Строка 1: |
Строка 1: |
| <languages/>
| | В обновлённом движке правил wb-rules присутствует ряд важных нововведений, касающихся логики написания сценариев. |
| <translate>
| |
|
| |
|
| == Изоляция сценариев == <!--T:3--> | | = Сценарии = |
| | == Постоянное хранилище данных == |
|
| |
|
| <!--T:4-->
| |
| Начиная с версии wb-rules 1.7, локальные переменные и функции, обьявленные в файле сценария не видны в других сценариях.
| |
| Таким образом, каждый сценарий может определять свои функции и переменные без риска изменить поведение других сценариев.
| |
|
| |
| === Пример === <!--T:5-->
| |
|
| |
| <!--T:6-->
| |
| В качестве примера приведём два сценария, одновременно запускаемых в движке правил.
| |
| Каждый сценарий определяет переменные и функции.
| |
|
| |
| <!--T:7-->
| |
| В предыдущих версиях wb-rules обращение к переменной, изменяемой в нескольких
| |
| файлах сценариев, может привести к неопределённому поведению. В версиях, начиная с 1.7,
| |
| поведение строго определено и такое же, как будто сценарий единственный в системе.
| |
|
| |
| <!--T:8-->
| |
| В комментариях указан вывод команд log для ранних версий и для актуальной версии. Обратите внимание на var перед переменными.
| |
|
| |
| <!--T:9-->
| |
| '''Сценарий 1 (rules1.js)'''
| |
| <syntaxhighlight lang="js">
| |
| var test1 = 42;
| |
|
| |
| <!--T:10-->
| |
| setInterval(function myFuncOne() {
| |
| log("myFuncOne called");
| |
| log("test1: {}", test1);
| |
| log("test2: {}", test2);
| |
| }, 5000);
| |
| </syntaxhighlight>
| |
|
| |
| <!--T:11-->
| |
| '''Сценарий 2 (rules2.js)'''
| |
| <syntaxhighlight lang="js">
| |
| var test1 = 84;
| |
| var test2 = "Hello";
| |
|
| |
| <!--T:12-->
| |
| setInterval(function myFuncTwo() {
| |
| log("myFuncTwo called");
| |
| log("test1: {}, test2: {}", test1, test2);
| |
| }, 5000);
| |
| </syntaxhighlight>
| |
|
| |
| <!--T:13-->
| |
| Было:
| |
| <pre>
| |
| 2019-01-05 17:29:50myFuncTwo called
| |
| 2019-01-05 17:29:50test1: 84, test2: Hello
| |
| 2019-01-05 17:29:50myFuncOne called
| |
| 2019-01-05 17:29:50test1: 84
| |
| 2019-01-05 17:29:50test2: Hello
| |
|
| |
| <!--T:14-->
| |
| </pre>
| |
|
| |
| <!--T:15-->
| |
| Стало:
| |
| <pre>
| |
| 2019-01-05 17:28:42myFuncTwo called
| |
| 2019-01-05 17:28:42test1: 84, test2: Hello
| |
| 2019-01-05 17:28:42myFuncOne called
| |
| 2019-01-05 17:28:42test1: 42
| |
| 2019-01-05 17:28:42ECMAScript error: ReferenceError: identifier 'test2' undefined
| |
| duk_js_var.c:1232
| |
| myFuncOne /etc/wb-rules/rules1.js:6 preventsyield
| |
| </pre>
| |
|
| |
| === Примечание === <!--T:16-->
| |
|
| |
| <!--T:17-->
| |
| В предыдущих версиях wb-rules для изоляции правил рекомендовалось использовать замыкание, т.е.
| |
| оборачивание кода сценария в конструкцию:
| |
| <syntaxhighlight lang="js">
| |
| (function() {
| |
| // код сценария идёт здесь
| |
| })();
| |
| </syntaxhighlight>
| |
|
| |
| <!--T:18-->
| |
| Начиная с версии 1.7, в подобной конструкции обычно нет необходимости. Тем не менее, старые сценарии,
| |
| использующие эту конструкцию, продолжат работу без изменений в поведении.
| |
|
| |
| === Обходные пути === <!--T:19-->
| |
|
| |
| <!--T:20-->
| |
| Если в вашей системе использовалось общее глобальное пространство для хранения общих данных и функций,
| |
| есть несколько способов реализации такого поведения:
| |
|
| |
| ==== Постоянное хранилище ==== <!--T:21-->
| |
|
| |
| <!--T:22-->
| |
| Для обмена данными также можно использовать глобальные постоянные хранилища (PersistentStorage).
| |
|
| |
| <!--T:23-->
| |
| '''Внимание:''' при использовании глобальных постоянных хранилищ может произойти совпадение имён, в
| |
| этом случае возможно труднообнаруживаемое нарушение поведения.
| |
|
| |
| <!--T:24-->
| |
| <syntaxhighlight lang="js">
| |
| var ps = new PersistentStorage("my-global-storage", {global: true});
| |
|
| |
| <!--T:25-->
| |
| /// ...
| |
|
| |
| <!--T:26-->
| |
| ps.myvar = "value"; // это значение доступно для всех пользователей хранилища с именем "my-global-storage"
| |
| </syntaxhighlight>
| |
|
| |
| ==== Прототип глобального объекта ==== <!--T:27-->
| |
|
| |
| <!--T:28-->
| |
| '''ВНИМАНИЕ:''' метод считается "грязным", т.к. все переменные и функции, опубликованные таким образом,
| |
| становятся доступными всем сценариям в системе. Старайтесь избегать этого способа. За неопределённое
| |
| поведение при использовании этого метода несёт ответственность сам программист.
| |
|
| |
| <!--T:29-->
| |
| Глобальные объекты всех сценариев имеют общий объект-''прототип'', в котором определены стандартные функции
| |
| wb-rules (такие, как defineRule, setTimeout и т.д.). Через него можно передавать переменные или функции
| |
| в общую область видимости.
| |
|
| |
| <!--T:30-->
| |
| <syntaxhighlight lang="js">
| |
| global.__proto__.myVar = 42; // теперь myVar - общая переменная для всех сценариев
| |
|
| |
| <!--T:31-->
| |
| // из других сценариев к переменной можно обращаться так
| |
| log("shared myVar: {}", myVar);
| |
|
| |
| <!--T:32-->
| |
| // или вот так, что чуть более аккуратно, т.к. однозначно показывает, где определена переменная
| |
| log("shared myVar: {}", global.__proto__.myVar);
| |
| </syntaxhighlight>
| |
|
| |
| <!--T:33-->
| |
| Правило поиска переменной в первом случае будет выглядеть так:
| |
|
| |
| <!--T:34-->
| |
| # Проверяем, есть ли myVar среди локальных переменных (определённой как var myVar = ...).
| |
| # Если нет, проверяем, есть ли myVar в глобальном объекте (определённой как myVar = ...).
| |
| # Если нет, проверяем, есть ли myVar в ''прототипе'' глобального объекта (определённой как global.__proto__.myVar).
| |
|
| |
| <!--T:35-->
| |
| Поиск останавливается, как только переменная найдена.
| |
|
| |
| <!--T:36-->
| |
| Таким образом, первый способ обращения будет работать только в том случае, если myVar не определена в верхних областях видимости.
| |
|
| |
| == Постоянное хранилище данных == <!--T:37-->
| |
|
| |
| <!--T:38-->
| |
| В wb-rules 1.7 добавлена поддержка постоянных хранилищ. По сути, это объекты, значения в которых будут сохраняться | | В wb-rules 1.7 добавлена поддержка постоянных хранилищ. По сути, это объекты, значения в которых будут сохраняться |
| даже при потере питания контроллера. Такие хранилища удобно использовать для хранения состояний или конфигурации. | | даже при потере питания контроллера. Такие хранилища удобно использовать для хранения состояний или конфигурации. |
|
| |
|
| <!--T:39-->
| |
| <syntaxhighlight lang="js"> | | <syntaxhighlight lang="js"> |
| var ps = new PersistentStorage("my-storage", { global: true }); | | var ps = new PersistentStorage("my-storage", { global: true }); |
|
| |
|
| <!--T:40-->
| |
| ps.key = "Hello World"; | | ps.key = "Hello World"; |
| log(ps.key); | | log(ps.key); |
| </syntaxhighlight> | | </syntaxhighlight> |
|
| |
|
| <!--T:41-->
| |
| Поддерживаются только глобальные хранилища, т.е. видимые по одному и тому же имени из всех файлов сценариев. | | Поддерживаются только глобальные хранилища, т.е. видимые по одному и тому же имени из всех файлов сценариев. |
|
| |
|
| == Виртуальные устройства == <!--T:42--> | | == Виртуальные устройства == |
|
| |
|
| <!--T:43-->
| |
| В предыдущих версиях wb-rules значения контролов виртуальных устройств хранились только в MQTT retained, что не очень надёжно (в случае | | В предыдущих версиях wb-rules значения контролов виртуальных устройств хранились только в MQTT retained, что не очень надёжно (в случае |
| потери питания данные могли быть легко утеряны). Начиная с версии 2.0, эти значения сохраняются также в специальное хранилище в постоянной | | потери питания данные могли быть легко утеряны). Начиная с версии 2.0, эти значения сохраняются также в специальное хранилище в постоянной |
| памяти и восстанавливаются при загрузке сценария. | | памяти и восстанавливаются при загрузке сценария. |
|
| |
|
| <!--T:44-->
| |
| Если необходимо каждый раз при перезагрузке скрипта восстанавливать строго определённое значение (т.е. не восстанавливать предыдущее сохранённое), | | Если необходимо каждый раз при перезагрузке скрипта восстанавливать строго определённое значение (т.е. не восстанавливать предыдущее сохранённое), |
| можно добавить в описание контрола поле forceDefault: | | можно добавить в описание контрола поле forceDefault: |
|
| |
|
| <!--T:45-->
| |
| <syntaxhighlight lang="js"> | | <syntaxhighlight lang="js"> |
| defineVirtualDevice("vdev", { | | defineVirtualDevice("vdev", { |
Строка 195: |
Строка 38: |
| }); | | }); |
| </syntaxhighlight> | | </syntaxhighlight> |
| </translate>
| |
В обновлённом движке правил wb-rules присутствует ряд важных нововведений, касающихся логики написания сценариев.
Сценарии
Постоянное хранилище данных
В wb-rules 1.7 добавлена поддержка постоянных хранилищ. По сути, это объекты, значения в которых будут сохраняться
даже при потере питания контроллера. Такие хранилища удобно использовать для хранения состояний или конфигурации.
var ps = new PersistentStorage("my-storage", { global: true });
ps.key = "Hello World";
log(ps.key);
Поддерживаются только глобальные хранилища, т.е. видимые по одному и тому же имени из всех файлов сценариев.
Виртуальные устройства
В предыдущих версиях wb-rules значения контролов виртуальных устройств хранились только в MQTT retained, что не очень надёжно (в случае
потери питания данные могли быть легко утеряны). Начиная с версии 2.0, эти значения сохраняются также в специальное хранилище в постоянной
памяти и восстанавливаются при загрузке сценария.
Если необходимо каждый раз при перезагрузке скрипта восстанавливать строго определённое значение (т.е. не восстанавливать предыдущее сохранённое),
можно добавить в описание контрола поле forceDefault:
defineVirtualDevice("vdev", {
...
cells: {
...
mycell: {
type: "value",
value: "10",
forceDefault: true // при каждой загрузке сценария поле mycell будет получать значение 10
}
}
});