Защищенные переходы¶
Часто вам нужно, чтобы переход между состояниями происходил только при соблюдении определенных условий состояния (конечных или расширенных) или события. Например, предположим, что вы создаете машину для формы поиска и хотите, чтобы поиск был разрешен только в том случае, если:
- пользователю разрешен поиск (
.canSearch
в этом примере) - поисковый запрос
query
не пустой
Это хороший вариант использования для «защищенного перехода», который является переходом, который происходит только в том случае, если выполняется какое-то условие (cond
). Переход с условием называется защищенным переходом (guarded transition).
Защитные функции¶
Защитная функция (condition function) (также известная как защитник — guard), указанная в свойстве .cond
перехода в виде строки или объекта условия со свойством {type: '...'}
и принимает 3 параметра:
Параметр | Тип | Описание |
---|---|---|
context | object | Контекст автомата |
event | object | сработавшее событие |
condMeta | object | мета-данные |
Объект condMeta
включает следующие свойства:
cond
— объект исходного состоянияstate
— состояние машины до перехода_event
— SCXML событие
Возвращает
true
или false
, что определяет, будет ли осуществлен переход.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
|
Перейдите на вкладку Events и отправьте событие типа {"type": "SEARCH", "query": "something"}
в визуализаторе:
https://stately.ai/viz?gist=09af23963bfa1767ce3900f2ae730029
Если cond
возвращает false
, то переход не будет выбран, и переход не будет происходить из этого узла состояния. Если все переходы в дочернем состоянии имеют защитные функции, которые возвращают false
и позволяют их выбрать, то событие будет передано в родительское состояние и обработано там.
Пример использования с контекстом context
:
1 2 3 4 5 6 7 8 9 10 11 |
|
Подсказка
Реализации защитных функций можно быстро прототипировать, задав свойство cond
прямо в конфигурации автомата:
1 2 3 4 5 6 |
|
Сериализация защитных функций¶
Защитные функции могут (и должны) быть сериализованы как строка или объект со свойством {type: '...'}
. Детали реализации защитной функции указаны в свойстве guards
параметров автомата, где key
— это тип type
защитной функции (указанный как строка или объект), а значение — это функция, которая принимает три параметра:
context
— текущий контекст автоматаevent
— событие, которое вызвало потенциальный переход-
guardMeta
— объект мета-данных о защитной функции и переходе:-
cond
— исходный объектcond
,
-
state
— состояние автомата то потенциального перехода
Рефакторинг приведенного выше примера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Кастомизированные защитные функции¶
Начиная с версии 4.4+
Иногда, предпочтительнее сериализовать в JSON не только состояние переходов, но и логику защитных функций, определив её как объект с соответствующими данными:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
Несколько защитных функций¶
Если вы хотите, чтобы одно событие переходило в разные состояния в определенных ситуациях, вы можете предоставить массив условных переходов. Каждый переход будет проверяться по порядку, и будет выполнен первый переход, для которого защитная функция cond
вернет true
.
Например, вы можете смоделировать дверь, которая прослушивает событие OPEN
, переходит в состояние 'opened'
, если вы администратор, или переходит в состояние 'closed.error'
, если значение alert
истинно, или переходит в состояние 'closed.idle'
в противном случае.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
|
Внимание
Функция cond
всегда должна быть чистой функцией, которая ссылается только на параметры контекста context
и события event
.
Подсказка
Не злоупотребляйте защитными условиями. Если что-то может быть представлено дискретно как два или более отдельных события вместо нескольких conds
для одного события, предпочтительнее избегать cond
и вместо этого использовать несколько типов событий.
Защитная функция in
¶
Свойство in
принимает идентификатор состояния в качестве аргумента и возвращает true
тогда и только тогда, когда этот узел состояния активен в текущем состоянии. Например, мы можем добавить защитную функцию к светофору:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
|
Когда защитная функция in
присутствует с другими защитными функциями cond
в том же переходе, все защитные функции должны вернуть true
, чтобы переход был выполнен.
Подсказка
Использование защитных функций in
обычно является признаком того, что автомат можно реорганизовать таким образом, чтобы в их использовании не было необходимости. По возможности избегайте защитных функций in
.