Ордена ленина институт прикладной математики им. М. В. Келдыша Российской Академии Наук

Вид материалаДокументы
3.2.Представление состояния приложения и управление изменениями
Подобный материал:
1   2   3   4   5   6

3.2.Представление состояния приложения и управление изменениями



Следующим шагом в поддержке архитектуры клиентской составляющей Веб-приложения является создание механизма для представления переменных состояния приложения, для чего уже есть необходимая основа – объект application, разделяемый всеми документами приложения. В рамках этого механизма должны быть представлены не только функции общей памяти, позволяющие ассоциировать названия переменных и их текущие значения, но и функции регистрации изменений (change management), позволяющие отслеживать транзакции при смене состояния и выделять, какие именно переменные модифицируются внутри транзакции.

В настоящем разделе мы не будем прибегать к детальному описанию выполненной нами реализации механизма поддержки глобальных переменных приложения, а остановимся только на тех существенных технических деталях, которые оказалось необходимо учитывать в ходе разработки (это представляется полезным для программистов, которые могут захотеть создать подобный механизм самостоятельно):
  • были отмечены проблемы с означиванием переменных приложения объектами " onclick="return false">
  • аналогичные проблемы возникают при означивании переменных ссылками на объекты DOM. Эти ссылки следует обнулять в момент, когда контекст, в котором они были созданы, завершает свою работу (такую функциональность можно встроить в реализацию метода unregisterWindow объекта application).
  • операция присваивания переменных состояния должна позволять изменить значения нескольких переменных одновременно. Для этого можно использовать нотацию JSON, передавая в качестве аргумента операции выражение вида {name:value,...}.
  • при выполнении присваивания переменной значения следует отслеживать ситуацию, когда это значение не изменяется. Для объектов такое сравнение должно быть «глубоким». Если значение не изменилось, то присваивание не должно отражаться в транзакции – в результате механизм приобретает функции «охранника», предотвращающего очевидные варианты зацикливания программы и, одновременно, оптимизирующего работу системы.


Интерфейс для доступа к переменным приложения должен включать в себя функции, позволяющие присваивать значения переменным и получать их текущие значения. Эти операции должны быть доступны в контексте любого из окон приложения (для этого достаточно включить их в application-worker.js):


value = appvarGet(name) // получить значение

appvarSet(name,value) // присвоить значение

appvarSet({name:value,...}) // присвоить значения

// нескольким переменным


Для иллюстрации вернемся к примеру, где была описана форма запроса для построения отчета с полями дат, заполняемых с помощью календаря. Поведение DHTML-компоненты – календаря в этом примере полностью определялось значением локальной переменной calendar_show_field, которая либо указывала на поле даты, в контексте которого календарь должен открываться, либо была пуста (тогда календарь переводится в «спрятанное» состояние). Поскольку эта переменная играет роль «синхронизатора» в поведении компонент, расположенных в разных документах приложения, ее следует представить в виде глобальной переменной, как показано в следующем фрагменте кода:











Заметим, что в принятых нами соглашениях имена глобальных переменных начинаются с символа $, чтобы синтаксически отличать эти идентификаторы от прочих переменных в программном коде. Причины такой идентификации станут понятны из следующего раздела.

3.3.Процедуры-триггеры



Взаимодействие компонент по схеме MVC представляет собой неэлементарный двухфазный процесс., ход которого на первой фазе нацелен на поддержание в актуальном состоянии значений переменных приложения. Эта задача, как показано выше, решается с помощью функций обработки событий, где модификация состояния приложения производится путем простого означивания соответствующих глобальных переменных.

На второй фазе MVC-взаимодействия в ответ на изменения текущих значений глобальных переменных должна производиться трансформация локального состояния DHTML-компонент и актуализация внешнего представления документов на экране. Для обеспечения такой формы поведения компонент должны быть реализованы функции наблюдения (по аналогии с функциями обработки событий), выполняющие следующие действия:
  • инициализация подписки, в обязанности которой входит найти наблюдаемый объект и подписаться на получение уведомлений об изменениях состояния этого объекта (при этом подписчик передает в качестве параметра перечень названий переменных, на изменения которых он будет реагировать);
  • инициализация состояния наблюдающих DHTML-компонент, когда на начальном этапе с использованием текущих значений наблюдаемых глобальных переменных производится актуализация локального состояния и, как следствие, внешнего представления документов;
  • рабочий цикл, в ходе которого наблюдаемый объект рассылает уведомления об изменениях своего состояния и производится синхронизация состояния наблюдающих компонент, подписавшихся на получение уведомления.
  • завершение подписки, когда «время жизни» компоненты заканчивается.


Конечно, такой функционал наблюдателя может быть реализован с помощью стандартных программных средств. Однако, представляемый в этом разделе механизм процедур-триггеров предлагает более облегченный способ реализации функций наблюдения и синхронизации состояния компонент визуального интерфейса, по сравнению со стандартными средствами. В конечном итоге мы рассчитываем хотя бы частично компенсировать очевидные с точки зрения Веб-программистов издержки от внедрения схемы MVC-взаимодействия - это примерно двукратное увеличение числа элементов программной обработки (учитывая необходимость реализации обработчиков событий и обработчиков-наблюдателей).

Процедура-триггер представляет собой простой фрагмент программного кода на языке " onclick="return false">...) – аналогично нотации, используемой для декларирования функций обработки событий (). Программный код, содержащийся в теле триггера, должен реализовывать содержательную часть задачи синхронизации – т.е. изменить локальное состояние DHTML-компоненты (или группы компонент), приведя ее в соответствие с текущими значениями глобальных переменных приложения. В теле этой процедуры можно объединить действия, которые производятся на шаге инициализации компоненты, с теми действиями, которые выполняются в рабочем цикле. Это не представляет затруднений, поскольку процедура-триггер может опрашивать как текущие значения переменных приложения, так и текущее состояние самой компоненты.

На практике код инициализации чаще всего не отличается от кода рабочего цикла. Например, в случае с календарем, триггер в документе-календаре может иметь вид:





При использовании механизма триггеров в задачи программиста входит только объявление триггеров и написание нужного программного кода для синхронизации. Все прочие задачи, необходимые для реализации функций наблюдения, берет на себя разѶдения переменных приложения, которые начинаются с символа доллар; полученный список переменных используется при регистрации подписки;
  • инициализация компоненты производится путем выполнения тела триггера, при этом гарантируется, что документ, в котором объявлен триггер, будет находиться в состоянии «загружен» (т.е. по наступлению события onload);
  • обслуживание рабочего цикла, которое также реализуется с помощью повторного выполнения тела триггера;
  • завершение подписки может быть отслежено по моменту завершения работы документа, в котором определен триггер.


    При выполнении тела триггера производится означивание всех вхождений переменных приложения их текущими значениями (или ссылками на значения). Интересно отметить, что триггеры будут корректно работать как с прямыми уведомлениями об изменениях (когда значения переменных состояния можно получать непосредственным опросом глобальных переменных), так и с отложенными уведомлениями (например, через события, которые помещаются в стандартную очередь событий операционной системы) – когда значения переменных необходимо извлекать из параметров события.

    Процедура-триггер может быть также объявлена динамически, с помощью вызова функций создания и удаления триггеров:


    createTrigger(triggerId,triggerBody) // создать триггер

    deleteTrigger(triggerId) // удалить триггер


    Реализация монитора для обслуживания триггеров не составляет большого труда. Выше мы фактически описали правила трансляции триггеров в процедуры на " onclick="return false">
  • т схеме взаимодействия слоев в парадигме MVC, где слой презентации не может менять состояние модели.