Движок правил wb-rules 1.7: различия между версиями
Fizikdaos (обсуждение | вклад) |
N.maslov (обсуждение | вклад) |
||
(не показано 28 промежуточных версий 4 участников) | |||
Строка 1: | Строка 1: | ||
В обновлённом движке правил wb-rules присутствует ряд важных нововведений, касающихся логики написания сценариев. | |||
== | = Нововведения = | ||
== Сценарии == | |||
=== | === Изоляция сценариев === | ||
Начиная с версии wb-rules 1.7, каждый файл сценария запускается в своём отдельном пространстве имён - '''контексте'''. Таким образом, каждый сценарий может определять | |||
свои функции и глобальные переменные без риска изменить поведение других сценариев. | |||
==== Пример ==== | |||
В качестве примера приведём два сценария, одновременно запускаемых в движке правил. | В качестве примера приведём два сценария, одновременно запускаемых в движке правил. | ||
Каждый сценарий определяет переменные и функции. | Каждый сценарий определяет глобальные переменные и функции. | ||
В предыдущих версиях wb-rules обращение к глобальной переменной, изменяемой в нескольких | |||
В предыдущих версиях wb-rules обращение к переменной, изменяемой в нескольких | |||
файлах сценариев, может привести к неопределённому поведению. В версиях, начиная с 1.7, | файлах сценариев, может привести к неопределённому поведению. В версиях, начиная с 1.7, | ||
поведение строго определено и такое же, как будто сценарий единственный в системе. | поведение строго определено и такое же, как будто сценарий единственный в системе. | ||
В комментариях указан вывод команд log для ранних версий и для актуальной версии. | |||
В комментариях указан вывод команд log для ранних версий и для актуальной версии | |||
'''Сценарий 1 (rules1.js)''' | '''Сценарий 1 (rules1.js)''' | ||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
test1 = 42; | |||
setTimeout(function myFuncOne() { | |||
log("myFuncOne called"); | log("myFuncOne called"); | ||
log("test1: {}", test1); | log("test1: {}, test2: {}", test1, test2); | ||
// раньше: test1: [либо 42, либо 84], test2: Hello | |||
}, | // теперь: test1: 42, test2: (undefined) | ||
// (будет выведена ошибка выполнения: ReferenceError: identifier 'test2' undefined) | |||
}, 1000); | |||
</syntaxhighlight> | </syntaxhighlight> | ||
'''Сценарий 2 (rules2.js)''' | '''Сценарий 2 (rules2.js)''' | ||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
test1 = 84; | |||
test2 = "Hello"; | |||
setTimeout(function myFuncTwo() { | |||
log("myFuncTwo called"); | log("myFuncTwo called"); | ||
log("test1: {}, test2: {}", test1, test2); | log("test1: {}, test2: {}", test1, test2); | ||
}, | // раньше: test1: [либо 42, либо 84], test2: Hello | ||
// теперь: test1: 84, test2: Hello | |||
}, 1000); | |||
</syntaxhighlight> | </syntaxhighlight> | ||
==== Примечание ==== | |||
В предыдущих версиях wb-rules для изоляции правил рекомендовалось использовать замыкание, т.е. | В предыдущих версиях wb-rules для изоляции правил рекомендовалось использовать замыкание, т.е. | ||
оборачивание кода сценария в конструкцию: | оборачивание кода сценария в конструкцию: | ||
Строка 83: | Строка 56: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Начиная с версии 1.7, в подобной конструкции нет необходимости. Тем не менее, старые сценарии, | |||
Начиная с версии 1.7, в подобной конструкции | |||
использующие эту конструкцию, продолжат работу без изменений в поведении. | использующие эту конструкцию, продолжат работу без изменений в поведении. | ||
=== | ==== Обходной путь ==== | ||
Если в вашей системе использовалось общее глобальное пространство для хранения общих данных и функций, | Если в вашей системе использовалось общее глобальное пространство для хранения общих данных и функций, | ||
есть несколько способов реализации такого поведения: | есть несколько способов реализации такого поведения: | ||
==== | ===== Использование модулей ===== | ||
см. Модули | |||
==== Прототип глобального объекта ==== | ===== Прототип глобального объекта ===== | ||
'''ВНИМАНИЕ:''' метод считается "грязным", т.к. все переменные и функции, опубликованные таким образом, | '''ВНИМАНИЕ:''' метод считается "грязным", т.к. все переменные и функции, опубликованные таким образом, | ||
становятся доступными всем сценариям в системе. Старайтесь избегать этого способа. За неопределённое | становятся доступными всем сценариям в системе. Старайтесь избегать этого способа. За неопределённое | ||
поведение при использовании этого метода несёт ответственность сам программист. | поведение при использовании этого метода несёт ответственность сам программист. | ||
Глобальные объекты всех сценариев имеют общий объект-''прототип'', в котором определены стандартные функции | Глобальные объекты всех сценариев имеют общий объект-''прототип'', в котором определены стандартные функции | ||
wb-rules (такие, как defineRule, setTimeout и т.д.). Через него можно передавать переменные или функции | wb-rules (такие, как defineRule, setTimeout и т.д.). Через него можно передавать переменные или функции | ||
в общую область видимости. | в общую область видимости. | ||
<syntaxhighlight lang="js"> | <syntaxhighlight lang="js"> | ||
global.__proto__.myVar = 42; // теперь myVar - общая переменная для всех сценариев | global.__proto__.myVar = 42; // теперь myVar - общая переменная для всех сценариев | ||
// из других сценариев к переменной можно обращаться так | // из других сценариев к переменной можно обращаться так | ||
log("shared myVar: {}", myVar); | log("shared myVar: {}", myVar); | ||
// или вот так, что чуть более аккуратно, т.к. однозначно показывает, где определена переменная | // или вот так, что чуть более аккуратно, т.к. однозначно показывает, где определена переменная | ||
log("shared myVar: {}", global.__proto__.myVar); | log("shared myVar: {}", global.__proto__.myVar); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Правило поиска переменной в первом случае будет выглядеть так: | Правило поиска переменной в первом случае будет выглядеть так: | ||
# Проверяем, есть ли myVar среди локальных переменных (определённой как var myVar = ...). | # Проверяем, есть ли myVar среди локальных переменных (определённой как var myVar = ...). | ||
# Если нет, проверяем, есть ли myVar в глобальном объекте (определённой как myVar = ...). | # Если нет, проверяем, есть ли myVar в глобальном объекте (определённой как myVar = ...). | ||
# Если нет, проверяем, есть ли myVar в ''прототипе'' глобального объекта (определённой как global.__proto__.myVar). | # Если нет, проверяем, есть ли myVar в ''прототипе'' глобального объекта (определённой как global.__proto__.myVar). | ||
Поиск останавливается, как только переменная найдена. | Поиск останавливается, как только переменная найдена. | ||
Таким образом, первый способ обращения будет работать только в том случае, если myVar не определена в верхних областях видимости. | Таким образом, первый способ обращения будет работать только в том случае, если myVar не определена в верхних областях видимости. | ||
Версия 14:36, 7 марта 2017
В обновлённом движке правил wb-rules присутствует ряд важных нововведений, касающихся логики написания сценариев.
Нововведения
Сценарии
Изоляция сценариев
Начиная с версии wb-rules 1.7, каждый файл сценария запускается в своём отдельном пространстве имён - контексте. Таким образом, каждый сценарий может определять свои функции и глобальные переменные без риска изменить поведение других сценариев.
Пример
В качестве примера приведём два сценария, одновременно запускаемых в движке правил. Каждый сценарий определяет глобальные переменные и функции.
В предыдущих версиях wb-rules обращение к глобальной переменной, изменяемой в нескольких файлах сценариев, может привести к неопределённому поведению. В версиях, начиная с 1.7, поведение строго определено и такое же, как будто сценарий единственный в системе.
В комментариях указан вывод команд log для ранних версий и для актуальной версии.
Сценарий 1 (rules1.js)
test1 = 42;
setTimeout(function myFuncOne() {
log("myFuncOne called");
log("test1: {}, test2: {}", test1, test2);
// раньше: test1: [либо 42, либо 84], test2: Hello
// теперь: test1: 42, test2: (undefined)
// (будет выведена ошибка выполнения: ReferenceError: identifier 'test2' undefined)
}, 1000);
Сценарий 2 (rules2.js)
test1 = 84;
test2 = "Hello";
setTimeout(function myFuncTwo() {
log("myFuncTwo called");
log("test1: {}, test2: {}", test1, test2);
// раньше: test1: [либо 42, либо 84], test2: Hello
// теперь: test1: 84, test2: Hello
}, 1000);
Примечание
В предыдущих версиях wb-rules для изоляции правил рекомендовалось использовать замыкание, т.е. оборачивание кода сценария в конструкцию:
(function() {
// код сценария идёт здесь
})();
Начиная с версии 1.7, в подобной конструкции нет необходимости. Тем не менее, старые сценарии, использующие эту конструкцию, продолжат работу без изменений в поведении.
Обходной путь
Если в вашей системе использовалось общее глобальное пространство для хранения общих данных и функций, есть несколько способов реализации такого поведения:
Использование модулей
см. Модули
Прототип глобального объекта
ВНИМАНИЕ: метод считается "грязным", т.к. все переменные и функции, опубликованные таким образом, становятся доступными всем сценариям в системе. Старайтесь избегать этого способа. За неопределённое поведение при использовании этого метода несёт ответственность сам программист.
Глобальные объекты всех сценариев имеют общий объект-прототип, в котором определены стандартные функции wb-rules (такие, как defineRule, setTimeout и т.д.). Через него можно передавать переменные или функции в общую область видимости.
global.__proto__.myVar = 42; // теперь myVar - общая переменная для всех сценариев
// из других сценариев к переменной можно обращаться так
log("shared myVar: {}", myVar);
// или вот так, что чуть более аккуратно, т.к. однозначно показывает, где определена переменная
log("shared myVar: {}", global.__proto__.myVar);
Правило поиска переменной в первом случае будет выглядеть так:
- Проверяем, есть ли myVar среди локальных переменных (определённой как var myVar = ...).
- Если нет, проверяем, есть ли myVar в глобальном объекте (определённой как myVar = ...).
- Если нет, проверяем, есть ли myVar в прототипе глобального объекта (определённой как global.__proto__.myVar).
Поиск останавливается, как только переменная найдена.
Таким образом, первый способ обращения будет работать только в том случае, если myVar не определена в верхних областях видимости.