diff --git a/docs/observable.ru.md b/docs/observable.ru.md --- a/docs/observable.ru.md +++ b/docs/observable.ru.md @@ -41,55 +41,40 @@ events.on( progress.close(); } ); - -// ожидание следующего события -let firstEvent = await events.next(); ``` -`Observable` можно создавать из событий другого объекта, например, виджета: +Пример создания `Observable` из событий другого объекта, например, виджета: ```ts -// клсс -class Canvas { - readonly mouseMove: IObservable<[number,number]> - - postCreate() { - // превращаем события виджета в Observable - this.mouseMove = new Observable<[number,number]>((notify) => { - this.mousePad.on('mousemove',(e) => notify([e.clientX, e.clientY]) ); - }); - } +postCreate() { + // превращаем события виджета в Observable + this.mouseMove = new Observable((notify) => { + this.moveArea.on('mousemove',(x) => notify(x.) ); + }); } ``` -Если объект инкапсулирует в себе `Observable`, он также может сохранить методы -для оповещения подписчиков для дальнейшего их использования внутри класса. +Пример инициализации `Observable` внутри класса и генерация событий: ```ts -// класс, который будет генерировать события местоположения -class PositionTracker implements IDestroyable { - // _nextPosition и _complete будут связаны с position при создании - // экземпляра PositionTracker. + +class PositionWidget extends Widget { _nextPosition: (pos: Position) => void + _complete: () => void - readonly position: IObservable + readonly position: Observable; - // конструктор - constructor(...args: any[]) { + constructor(...args[]) { super(args); - // создаем Observable this.position = new Observable((notify, error, complete) => { - // сохраняем методы для оповещения о новом местоположении this._nextPosition = notify; - // метод об оповещении конца потока событий this._complete = complete }); } - // метод для очистки ресурсов destroy() { this._complete(); @@ -97,39 +82,4 @@ class PositionTracker implements IDestro } } -``` - -## Observable и последовательности - -Можно сичтать, что `Observable` это некоторая аналогия итератора только в -парадигме событийного (или реактивного) программировния. Следует также понимать, -что при переходе от синхронного процедурного программирования к событийному так -же меняется и направление управления (Inverse Of Control), что означает -следующее: - -* при работе с итераторами клиенты сами определяют момент чтения следующего - элемента последовательности. -* при работе с `Observable` клиенты вынуждены обрабатывать эти события по мере - их поступления и не могут на это повлиять. - -Последний пункт можно изменить применив, например, буффер или канал с -состоянием, т.е. очередь, но данные механизмы выходят за рамки простого шаблона -наблюдателя. - -```ts -while(1) { - // ожидаем следующее событие, по сути это подписка только на одно событие - let next = await events.next(); - - // такой цикл может пропускать сообщения, поскольку асинхронная операция - // позволит возобновить создание новых событий, на которые мы не подписаны - await processEvent(next); - - // не только асинхронные операции могут привести к пропуску события - // например вызов метода, который приводит к созданию события так же - // приведет к тому, что созданное событие не будет обработано в текущем - // цикле - doSmthAndRiseEvent(); -} - ``` \ No newline at end of file diff --git a/test/js/plan.js b/test/js/plan.js --- a/test/js/plan.js +++ b/test/js/plan.js @@ -1,2 +1,3 @@ -define(["./ActivatableTests", "./trace-test", "./TraceSourceTests", "./CancellationTests"]); -//define(["./CancellationTests"]); \ No newline at end of file +//define(["./ActivatableTests", "./trace-test", "./TraceSourceTests", "./CancellationTests"]); +//define(["./CancellationTests"]); +define(["./ObservableTests"]); \ No newline at end of file diff --git a/test/ts/ObservableTests.ts b/test/ts/ObservableTests.ts new file mode 100644 --- /dev/null +++ b/test/ts/ObservableTests.ts @@ -0,0 +1,36 @@ +import { TraceSource, DebugLevel } from '@implab/core/log/TraceSource' +import * as tape from 'tape'; +import { TapeWriter, delay } from './TestTraits'; +import { Observable } from '@implab/core/Observable'; +import { IObservable } from '@implab/core/interfaces'; + +let trace = TraceSource.get("ObservableTests"); + +tape('events sequence example', async t => { + + + let events: IObservable + + let done = new Promise((resolve) => { + events = new Observable(async (notify, fail, complete) => { + for (let i = 0; i < 10; i++) { + await delay(0); + notify(i); + } + resolve(); + }); + }); + + let count = 0; + events.on(x => count = count + x); + + let first = await events.next(); + + t.equals(first, 0, "the first event"); + + await done; + + t.equals(count, 45, "the summ of the evetns"); + + t.end(); +}); \ No newline at end of file