Движок правил wb-rules 1.7: различия между версиями

Нет описания правки
Строка 2: Строка 2:


= Сценарии =
= Сценарии =
== Изоляция сценариев ==
Начиная с версии wb-rules 1.7, локальные переменные и функции, обьявленные в файле сценария не видны в других сценариях.
Таким образом, каждый сценарий может определять свои функции и переменные без риска изменить поведение других сценариев.
=== Пример ===
В качестве примера приведём два сценария, одновременно запускаемых в движке правил.
Каждый сценарий определяет переменные и функции.
В предыдущих версиях wb-rules обращение к переменной, изменяемой в нескольких
файлах сценариев, может привести к неопределённому поведению. В версиях, начиная с 1.7,
поведение строго определено и такое же, как будто сценарий единственный в системе.
В комментариях указан вывод команд log для ранних версий и для актуальной версии. Обратите внимание на var перед переменными.
'''Сценарий 1 (rules1.js)'''
<syntaxhighlight lang="js">
var test1 = 42;
setInterval(function myFuncOne() {
    log("myFuncOne called");
    log("test1: {}", test1);
    log("test2: {}", test2);
}, 5000);
</syntaxhighlight>
'''Сценарий 2 (rules2.js)'''
<syntaxhighlight lang="js">
var test1 = 84;
var test2 = "Hello";
setInterval(function myFuncTwo() {
    log("myFuncTwo called");
    log("test1: {}, test2: {}", test1, test2);
}, 5000);
</syntaxhighlight>
Было:
<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
</pre>
Стало:
<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>
=== Примечание ===
В предыдущих версиях wb-rules для изоляции правил рекомендовалось использовать замыкание, т.е.
оборачивание кода сценария в конструкцию:
<syntaxhighlight lang="js">
(function() {
    // код сценария идёт здесь
})();
</syntaxhighlight>
Начиная с версии 1.7, в подобной конструкции обычно нет необходимости. Тем не менее, старые сценарии,
использующие эту конструкцию, продолжат работу без изменений в поведении.
=== Обходные пути ===
Если в вашей системе использовалось общее глобальное пространство для хранения общих данных и функций,
есть несколько способов реализации такого поведения:
==== Постоянное хранилище ====
Для обмена данными также можно использовать глобальные постоянные хранилища (PersistentStorage).
'''Внимание:''' при использовании глобальных постоянных хранилищ может произойти совпадение имён, в
этом случае возможно труднообнаруживаемое нарушение поведения.
<syntaxhighlight lang="js">
var ps = new PersistentStorage("my-global-storage", {global: true});
/// ...
ps.myvar = "value"; // это значение доступно для всех пользователей хранилища с именем "my-global-storage"
</syntaxhighlight>
==== Прототип глобального объекта ====
'''ВНИМАНИЕ:''' метод считается "грязным", т.к. все переменные и функции, опубликованные таким образом,
становятся доступными всем сценариям в системе. Старайтесь избегать этого способа. За неопределённое
поведение при использовании этого метода несёт ответственность сам программист.
Глобальные объекты всех сценариев имеют общий объект-''прототип'', в котором определены стандартные функции
wb-rules (такие, как defineRule, setTimeout и т.д.). Через него можно передавать переменные или функции
в общую область видимости.
<syntaxhighlight lang="js">
global.__proto__.myVar = 42; // теперь myVar - общая переменная для всех сценариев
// из других сценариев к переменной можно обращаться так
log("shared myVar: {}", myVar);
// или вот так, что чуть более аккуратно, т.к. однозначно показывает, где определена переменная
log("shared myVar: {}", global.__proto__.myVar);
</syntaxhighlight>
Правило поиска переменной в первом случае будет выглядеть так:
# Проверяем, есть ли myVar среди локальных переменных (определённой как var myVar = ...).
# Если нет, проверяем, есть ли myVar в глобальном объекте (определённой как myVar = ...).
# Если нет, проверяем, есть ли myVar в ''прототипе'' глобального объекта (определённой как global.__proto__.myVar).
Поиск останавливается, как только переменная найдена.
Таким образом, первый способ обращения будет работать только в том случае, если myVar не определена в верхних областях видимости.
== Постоянное хранилище данных ==
== Постоянное хранилище данных ==