##// END OF EJS Templates
wip migrating on new typescript build plugin
wip migrating on new typescript build plugin

File last commit:

r133:09ea4b9e3735 ioc ts support
r174:b00d3153045c default
Show More
observable.md
182 lines | 8.0 KiB | text/x-minidsrc | MarkdownLexer
andrei
spelling fixes
r25 # Observable
Универсальный способ организации потока сообщений. Данный механизм может
использоваться для оповещения об изменениях состояний объектов или для доставки
самостоятельных событий, например, связанных с действиями пользователя.
Является реализацией классического шаблона наблюдателя с возможность сообщить
cin
working on fluent configuration
r133 о конце потока событий. Данная реализация не содержит никаких дополнительных
andrei
spelling fixes
r25 функций, таких как фильтрация, канал с состоянием, преобразования сообщений и
т.п. Это сделано специально, чтобы реализация оставалась максимально простой.
Пример того, как можно создать последовательность из 10 событий:
```ts
var events = new Observable(async (notify, error, complete) => {
// цикл в котором возникает событие
for(let i = 0; i < 10; i++) {
await delay(1000);
// в качестве данных передается номер события
notify(i);
}
// по окончании последовательности информируем, что событий больше не будет
cin
working on fluent configuration
r133 complete();
andrei
spelling fixes
r25 });
// создаем окно с отображением хода событий
var progress = showProgress({ min: 0, max: 9, current: 0});
// подписываемся на события
events.on(
// обработчик очередного события
msg => {
progress.setValue(msg);
cin
the documentation on observables is added...
r26 }.
andrei
spelling fixes
r25 // обработчик ошибки
e => {
progress.showError(e);
},
// обработчик конца потока
() => {
progress.close();
}
);
cin
the documentation on observables is added...
r26
// ожидание следующего события
let firstEvent = await events.next();
andrei
spelling fixes
r25 ```
cin
the documentation on observables is added...
r26 `Observable` можно создавать из событий другого объекта, например, виджета:
andrei
spelling fixes
r25
```ts
cin
working on fluent configuration
r133 // класс
cin
the documentation on observables is added...
r26 class Canvas {
cin
working on fluent configuration
r133 mouseMove: IObservable<[number,number]>;
cin
the documentation on observables is added...
r26
postCreate() {
// превращаем события виджета в Observable
this.mouseMove = new Observable<[number,number]>((notify) => {
this.mousePad.on('mousemove',(e) => notify([e.clientX, e.clientY]) );
});
}
andrei
spelling fixes
r25 }
```
cin
the documentation on observables is added...
r26 Если объект инкапсулирует в себе `Observable`, он также может сохранить методы
для оповещения подписчиков для дальнейшего их использования внутри класса.
andrei
spelling fixes
r25
```ts
cin
the documentation on observables is added...
r26 // класс, который будет генерировать события местоположения
class PositionTracker implements IDestroyable {
// _nextPosition и _complete будут связаны с position при создании
// экземпляра PositionTracker.
andrei
spelling fixes
r25 _nextPosition: (pos: Position) => void
_complete: () => void
cin
the documentation on observables is added...
r26 readonly position: IObservable<Position>
andrei
spelling fixes
r25
cin
the documentation on observables is added...
r26 // конструктор
constructor(...args: any[]) {
andrei
spelling fixes
r25 super(args);
cin
the documentation on observables is added...
r26 // создаем Observable
andrei
spelling fixes
r25 this.position = new Observable<Position>((notify, error, complete) => {
cin
the documentation on observables is added...
r26 // сохраняем методы для оповещения о новом местоположении
andrei
spelling fixes
r25 this._nextPosition = notify;
cin
the documentation on observables is added...
r26 // метод об оповещении конца потока событий
andrei
spelling fixes
r25 this._complete = complete
});
}
cin
the documentation on observables is added...
r26 // метод для очистки ресурсов
andrei
spelling fixes
r25 destroy() {
this._complete();
super();
}
}
cin
the documentation on observables is added...
r26 ```
andrei
spelling fixes
r25
cin
working on fluent configuration
r133 Существует также несколько вариантов получения сообщений
cin
the documentation on observables is added...
r26
```ts
// регистрация метода для получений событий
let subscription = pushEvents.on((msg) => {
displayPopup(msg);
});
// подписку можно отменить, после чего обработчики больше не будут вызываться
subcription.destroy();
// если требуется получить только одно сообщение можно использовать
// асинхронный метод next(ct?: ICancellation)
let msg = await pushEvents.next();
// пример метода для получения координат с карты, который использует
// событие нажатия мышью для определения координат.
class Map {
/**
Получает координаты по щелчку мыши.
@async
@returns [lon,lat]
*/
async peekCoordinates(ct: ICancellation = Cancellation.none) {
// получаем событие клика
let evt = this.viewport.click.next(ct);
cin
working on support commonjs modules format
r59
cin
the documentation on observables is added...
r26 // преобразуем позицию на экране в координаты карты
cin
working on fluent configuration
r133 return this.clientToCoordinates([evt.clientX,evt.clientY]);
cin
the documentation on observables is added...
r26 }
}
let map : Map; // где-то объявлено
// пример получения координат с карты
let coords = await map.peekCoordinates();
```
## Observable и последовательности
cin
working on fluent configuration
r133 Можно считать, что `Observable` это некоторая аналогия итератора только в
парадигме событийного (или реактивного) программирования. Следует также понимать,
cin
the documentation on observables is added...
r26 что при переходе от синхронного процедурного программирования к событийному так
же меняется и направление управления (Inverse Of Control), что означает
следующее:
* при работе с итераторами клиенты сами определяют момент чтения следующего
элемента последовательности.
* при работе с `Observable` клиенты вынуждены обрабатывать эти события по мере
их поступления и не могут на это повлиять.
cin
working on fluent configuration
r133 Последний пункт можно изменить применив, например, буфер или канал с
cin
the documentation on observables is added...
r26 состоянием, т.е. очередь, но данные механизмы выходят за рамки простого шаблона
наблюдателя.
```ts
// обработка в цикле не гарантирует получения всех сообщений
while(1) {
// ожидаем следующее событие, по сути это подписка только на одно событие
let next = await events.next();
// такой цикл может пропускать сообщения, поскольку асинхронная операция
// позволит возобновить создание новых событий, на которые мы не подписаны
await processEvent(next);
// не только асинхронные операции могут привести к пропуску события
// например вызов метода, который приводит к созданию события так же
// приведет к тому, что созданное событие не будет обработано в текущем
// цикле
doSmthAndRiseEvent();
}
// для получения всех сообщений нужно регистрировать подписчика
events.on((data) => {
// будет вызван для всех сообщений
processEvent(data);
});
cin
working on fluent configuration
r133 ```