3690
правок
(→Модули) |
|||
Строка 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 не определена в верхних областях видимости. | |||
== Постоянное хранилище данных == | == Постоянное хранилище данных == | ||