##// END OF EJS Templates
spelling fixes
andrei -
r25:35af87458b03 propose observables
parent child
Show More
1 NO CONTENT: file renamed from docs/cancellations.ru.md to docs/en/cancellations.md
NO CONTENT: file renamed from docs/cancellations.ru.md to docs/en/cancellations.md
@@ -1,85 +1,85
1 # Observable
1 # Observable
2
2
3 Универсальный способ организации потока сообщений. Данный механизм может
3 Универсальный способ организации потока сообщений. Данный механизм может
4 использоваться для оповещения об изменениях состояний объектов или для доставки
4 использоваться для оповещения об изменениях состояний объектов или для доставки
5 самостоятельных событий, например, связанных с действиями пользователя.
5 самостоятельных событий, например, связанных с действиями пользователя.
6
6
7 Является реализацией классического шаблона наблюдателя с возможность сообщить
7 Является реализацией классического шаблона наблюдателя с возможность сообщить
8 о коце потока событий. Данная реализация не содержит никаких дополнительных
8 о коце потока событий. Данная реализация не содержит никаких дополнительных
9 функций, таких как фильтрация, канал с состоянием, преобразования сообщений и
9 функций, таких как фильтрация, канал с состоянием, преобразования сообщений и
10 т.п. Это сделано специально, чтобы реализация оставалась максимально простой.
10 т.п. Это сделано специально, чтобы реализация оставалась максимально простой.
11
11
12 Пример того, как можно создать последовательность из 10 событий:
12 Пример того, как можно создать последовательность из 10 событий:
13
13
14 ```ts
14 ```ts
15 var events = new Observable(async (notify, error, complete) => {
15 var events = new Observable(async (notify, error, complete) => {
16 // цикл в котором возникает событие
16 // цикл в котором возникает событие
17 for(let i = 0; i < 10; i++) {
17 for(let i = 0; i < 10; i++) {
18 await delay(1000);
18 await delay(1000);
19 // в качестве данных передается номер события
19 // в качестве данных передается номер события
20 notify(i);
20 notify(i);
21 }
21 }
22 // по окончании последовательности информируем, что событий больше не будет
22 // по окончании последовательности информируем, что событий больше не будет
23 compelte();
23 compelte();
24 });
24 });
25
25
26 // создаем окно с отображением хода событий
26 // создаем окно с отображением хода событий
27 var progress = showProgress({ min: 0, max: 9, current: 0});
27 var progress = showProgress({ min: 0, max: 9, current: 0});
28
28
29 // подписываемся на события
29 // подписываемся на события
30 events.on(
30 events.on(
31 // обработчик очередного события
31 // обработчик очередного события
32 msg => {
32 msg => {
33 progress.setValue(msg);
33 progress.setValue(msg);
34 }.
34 },
35 // обработчик ошибки
35 // обработчик ошибки
36 e => {
36 e => {
37 progress.showError(e);
37 progress.showError(e);
38 },
38 },
39 // обработчик конца потока
39 // обработчик конца потока
40 () => {
40 () => {
41 progress.close();
41 progress.close();
42 }
42 }
43 );
43 );
44 ```
44 ```
45
45
46 Пример создания `Observable` из событий другого объекта, например, виджета:
46 Пример создания `Observable` из событий другого объекта, например, виджета:
47
47
48 ```ts
48 ```ts
49 postCreate() {
49 postCreate() {
50 // превращаем события виджета в Observable
50 // превращаем события виджета в Observable
51 this.mouseMove = new Observable((notify) => {
51 this.mouseMove = new Observable((notify) => {
52 this.moveArea.on('mousemove',(x) => notify(x.) );
52 this.moveArea.on('mousemove',(x) => notify(x.) );
53 });
53 });
54 }
54 }
55
55
56 ```
56 ```
57
57
58 Пример инициализации `Observable` внутри класса и генерация событий:
58 Пример инициализации `Observable` внутри класса и генерация событий:
59
59
60 ```ts
60 ```ts
61
61
62 class PositionWidget extends Widget {
62 class PositionWidget extends Widget {
63 _nextPosition: (pos: Position) => void
63 _nextPosition: (pos: Position) => void
64
64
65 _complete: () => void
65 _complete: () => void
66
66
67 readonly position: Observable<Position>;
67 readonly position: Observable<Position>;
68
68
69 constructor(...args[]) {
69 constructor(...args[]) {
70 super(args);
70 super(args);
71
71
72 this.position = new Observable<Position>((notify, error, complete) => {
72 this.position = new Observable<Position>((notify, error, complete) => {
73 this._nextPosition = notify;
73 this._nextPosition = notify;
74 this._complete = complete
74 this._complete = complete
75 });
75 });
76 }
76 }
77
77
78 destroy() {
78 destroy() {
79 this._complete();
79 this._complete();
80
80
81 super();
81 super();
82 }
82 }
83 }
83 }
84
84
85 ``` No newline at end of file
85 ```
1 NO CONTENT: file copied from docs/cancellations.ru.md to docs/ru/cancellations.md
NO CONTENT: file copied from docs/cancellations.ru.md to docs/ru/cancellations.md
@@ -1,85 +1,85
1 # Observable
1 # Observable
2
2
3 Универсальный способ организации потока сообщений. Данный механизм может
3 Универсальный способ организации потока сообщений. Данный механизм может
4 использоваться для оповещения об изменениях состояний объектов или для доставки
4 использоваться для оповещения об изменениях состояний объектов или для доставки
5 самостоятельных событий, например, связанных с действиями пользователя.
5 самостоятельных событий, например, связанных с действиями пользователя.
6
6
7 Является реализацией классического шаблона наблюдателя с возможность сообщить
7 Является реализацией классического шаблона наблюдателя с возможность сообщить
8 о коце потока событий. Данная реализация не содержит никаких дополнительных
8 о коце потока событий. Данная реализация не содержит никаких дополнительных
9 функций, таких как фильтрация, канал с состоянием, преобразования сообщений и
9 функций, таких как фильтрация, канал с состоянием, преобразования сообщений и
10 т.п. Это сделано специально, чтобы реализация оставалась максимально простой.
10 т.п. Это сделано специально, чтобы реализация оставалась максимально простой.
11
11
12 Пример того, как можно создать последовательность из 10 событий:
12 Пример того, как можно создать последовательность из 10 событий:
13
13
14 ```ts
14 ```ts
15 var events = new Observable(async (notify, error, complete) => {
15 var events = new Observable(async (notify, error, complete) => {
16 // цикл в котором возникает событие
16 // цикл в котором возникает событие
17 for(let i = 0; i < 10; i++) {
17 for(let i = 0; i < 10; i++) {
18 await delay(1000);
18 await delay(1000);
19 // в качестве данных передается номер события
19 // в качестве данных передается номер события
20 notify(i);
20 notify(i);
21 }
21 }
22 // по окончании последовательности информируем, что событий больше не будет
22 // по окончании последовательности информируем, что событий больше не будет
23 compelte();
23 compelte();
24 });
24 });
25
25
26 // создаем окно с отображением хода событий
26 // создаем окно с отображением хода событий
27 var progress = showProgress({ min: 0, max: 9, current: 0});
27 var progress = showProgress({ min: 0, max: 9, current: 0});
28
28
29 // подписываемся на события
29 // подписываемся на события
30 events.on(
30 events.on(
31 // обработчик очередного события
31 // обработчик очередного события
32 msg => {
32 msg => {
33 progress.setValue(msg);
33 progress.setValue(msg);
34 }.
34 },
35 // обработчик ошибки
35 // обработчик ошибки
36 e => {
36 e => {
37 progress.showError(e);
37 progress.showError(e);
38 },
38 },
39 // обработчик конца потока
39 // обработчик конца потока
40 () => {
40 () => {
41 progress.close();
41 progress.close();
42 }
42 }
43 );
43 );
44 ```
44 ```
45
45
46 Пример создания `Observable` из событий другого объекта, например, виджета:
46 Пример создания `Observable` из событий другого объекта, например, виджета:
47
47
48 ```ts
48 ```ts
49 postCreate() {
49 postCreate() {
50 // превращаем события виджета в Observable
50 // превращаем события виджета в Observable
51 this.mouseMove = new Observable((notify) => {
51 this.mouseMove = new Observable((notify) => {
52 this.moveArea.on('mousemove',(x) => notify(x.) );
52 this.moveArea.on('mousemove',(x) => notify(x.) );
53 });
53 });
54 }
54 }
55
55
56 ```
56 ```
57
57
58 Пример инициализации `Observable` внутри класса и генерация событий:
58 Пример инициализации `Observable` внутри класса и генерация событий:
59
59
60 ```ts
60 ```ts
61
61
62 class PositionWidget extends Widget {
62 class PositionWidget extends Widget {
63 _nextPosition: (pos: Position) => void
63 _nextPosition: (pos: Position) => void
64
64
65 _complete: () => void
65 _complete: () => void
66
66
67 readonly position: Observable<Position>;
67 readonly position: Observable<Position>;
68
68
69 constructor(...args[]) {
69 constructor(...args[]) {
70 super(args);
70 super(args);
71
71
72 this.position = new Observable<Position>((notify, error, complete) => {
72 this.position = new Observable<Position>((notify, error, complete) => {
73 this._nextPosition = notify;
73 this._nextPosition = notify;
74 this._complete = complete
74 this._complete = complete
75 });
75 });
76 }
76 }
77
77
78 destroy() {
78 destroy() {
79 this._complete();
79 this._complete();
80
80
81 super();
81 super();
82 }
82 }
83 }
83 }
84
84
85 ``` No newline at end of file
85 ```
@@ -1,193 +1,193
1 import { IObservable, IDestroyable, ICancellation } from './interfaces';
1 import { IObservable, IDestroyable, ICancellation } from './interfaces';
2 import { Cancellation } from './Cancellation'
2 import { Cancellation } from './Cancellation'
3 import { argumentNotNull } from './safe';
3 import { argumentNotNull } from './safe';
4
4
5
5
6 interface Handler<T> {
6 interface Handler<T> {
7 (x: T): void
7 (x: T): void
8 }
8 }
9
9
10 interface Initializer<T> {
10 interface Initializer<T> {
11 (notify: Handler<T>, error?: (e: any) => void, complete?: () => void): void;
11 (notify: Handler<T>, error?: (e: any) => void, complete?: () => void): void;
12 }
12 }
13
13
14 // TODO: think about to move this interfaces.ts and make it public
14 // TODO: think about to move this interfaces.ts and make it public
15 interface IObserver<T> {
15 interface IObserver<T> {
16 next(event: T): void
16 next(event: T): void
17
17
18 error(e: any): void
18 error(e: any): void
19
19
20 complete(): void
20 complete(): void
21 }
21 }
22
22
23 const noop = () => {};
23 const noop = () => {};
24
24
25 export class Observable<T> implements IObservable<T> {
25 export class Observable<T> implements IObservable<T> {
26 private _once = new Array<IObserver<T>>();
26 private _once = new Array<IObserver<T>>();
27
27
28 private _observers = new Array<IObserver<T>>();
28 private _observers = new Array<IObserver<T>>();
29
29
30
30
31 private _complete: boolean
31 private _complete: boolean
32
32
33 private _error: any
33 private _error: any
34
34
35 constructor(func?: Initializer<T>) {
35 constructor(func?: Initializer<T>) {
36 if (func)
36 if (func)
37 func(
37 func(
38 this._notifyNext.bind(this),
38 this._notifyNext.bind(this),
39 this._notifyError.bind(this),
39 this._notifyError.bind(this),
40 this._notifyCompleted.bind(this)
40 this._notifyCompleted.bind(this)
41 );
41 );
42 }
42 }
43
43
44 /**
44 /**
45 * Registers handlers for the current observable object.
45 * Registers handlers for the current observable object.
46 *
46 *
47 * @param next the handler for events
47 * @param next the handler for events
48 * @param error the handler for a error
48 * @param error the handler for a error
49 * @param complete the handler for a completion
49 * @param complete the handler for a completion
50 * @returns {IDestroyable} the handler for the current subscription, this
50 * @returns {IDestroyable} the handler for the current subscription, this
51 * handler can be used to unsubscribe from events.
51 * handler can be used to unsubscribe from events.
52 *
52 *
53 */
53 */
54 on(next: Handler<T>, error?: Handler<any>, complete?: () => void): IDestroyable {
54 on(next: Handler<T>, error?: Handler<any>, complete?: () => void): IDestroyable {
55 argumentNotNull(next, "next");
55 argumentNotNull(next, "next");
56
56
57 let me = this;
57 let me = this;
58
58
59 let observer: IObserver<T> & IDestroyable = {
59 let observer: IObserver<T> & IDestroyable = {
60 next: next,
60 next: next,
61 error: error ? error.bind(null) : noop,
61 error: error ? error.bind(null) : noop,
62 complete: complete ? complete.bind(null) : noop,
62 complete: complete ? complete.bind(null) : noop,
63
63
64 destroy() {
64 destroy() {
65 me._removeObserver(this);
65 me._removeObserver(this);
66 }
66 }
67 }
67 };
68
68
69 this._addObserver(observer);
69 this._addObserver(observer);
70
70
71
71
72 return observer;
72 return observer;
73 }
73 }
74
74
75 private _addObserver(observer: IObserver<T>) {
75 private _addObserver(observer: IObserver<T>) {
76 if (this._complete) {
76 if (this._complete) {
77 try {
77 try {
78 if (this._error)
78 if (this._error)
79 observer.error(this._error);
79 observer.error(this._error);
80 else
80 else
81 observer.complete();
81 observer.complete();
82 } catch (e) {
82 } catch (e) {
83 this.onObserverException(e);
83 this.onObserverException(e);
84 }
84 }
85 } else {
85 } else {
86 this._observers.push(observer);
86 this._observers.push(observer);
87 }
87 }
88 }
88 }
89
89
90 /**
90 /**
91 * Waits for the next event. This method can't be used to read messages
91 * Waits for the next event. This method can't be used to read messages
92 * as a sequence since it can skip some messages between calls.
92 * as a sequence since it can skip some messages between calls.
93 *
93 *
94 * @param ct a cancellation token
94 * @param ct a cancellation token
95 */
95 */
96 next(ct: ICancellation = Cancellation.none): Promise<T> {
96 next(ct: ICancellation = Cancellation.none): Promise<T> {
97 return new Promise<T>((resolve, reject) => {
97 return new Promise<T>((resolve, reject) => {
98 let observer: IObserver<T> = {
98 let observer: IObserver<T> = {
99 next: resolve,
99 next: resolve,
100 error: reject,
100 error: reject,
101 complete: () => reject("No more events are available")
101 complete: () => reject("No more events are available")
102 };
102 };
103
103
104 if (this._addOnce(observer) && ct.isSupported()) {
104 if (this._addOnce(observer) && ct.isSupported()) {
105 ct.register((e) => {
105 ct.register((e) => {
106 this._removeOnce(observer);
106 this._removeOnce(observer);
107 reject(e);
107 reject(e);
108 });
108 });
109 }
109 }
110 });
110 });
111 }
111 }
112
112
113 private _addOnce(observer: IObserver<T>) {
113 private _addOnce(observer: IObserver<T>) {
114 if (this._complete) {
114 if (this._complete) {
115 try {
115 try {
116 if (this._error)
116 if (this._error)
117 observer.error(this._error);
117 observer.error(this._error);
118 else
118 else
119 observer.complete();
119 observer.complete();
120 } catch (e) {
120 } catch (e) {
121 this.onObserverException(e);
121 this.onObserverException(e);
122 }
122 }
123 return false;
123 return false;
124 }
124 }
125
125
126 this._once.push(observer);
126 this._once.push(observer);
127 return true;
127 return true;
128 }
128 }
129
129
130 protected onObserverException(e: any) {
130 protected onObserverException(e: any) {
131 }
131 }
132
132
133 private _removeOnce(d: IObserver<T>) {
133 private _removeOnce(d: IObserver<T>) {
134 let i = this._once.indexOf(d);
134 let i = this._once.indexOf(d);
135 if (i >= 0)
135 if (i >= 0)
136 this._once.splice(i, 1);
136 this._once.splice(i, 1);
137 }
137 }
138
138
139 private _removeObserver(d: IObserver<T>) {
139 private _removeObserver(d: IObserver<T>) {
140 let i = this._observers.indexOf(d);
140 let i = this._observers.indexOf(d);
141 if (i >= 0)
141 if (i >= 0)
142 this._observers.splice(i, 1);
142 this._observers.splice(i, 1);
143 }
143 }
144
144
145 private _notify(guard: (observer: IObserver<T>) => void) {
145 private _notify(guard: (observer: IObserver<T>) => void) {
146 if (this._once.length) {
146 if (this._once.length) {
147 for (let i = 0; i < this._once.length; i++)
147 for (let i = 0; i < this._once.length; i++)
148 guard(this._once[i]);
148 guard(this._once[i]);
149 this._once = [];
149 this._once = [];
150 }
150 }
151
151
152 for (let i = 0; i < this._observers.length; i++)
152 for (let i = 0; i < this._observers.length; i++)
153 guard(this._observers[i]);
153 guard(this._observers[i]);
154 }
154 }
155
155
156 protected _notifyNext(evt: T) {
156 protected _notifyNext(evt: T) {
157 let guard = (observer: IObserver<T>) => {
157 let guard = (observer: IObserver<T>) => {
158 try {
158 try {
159 observer.next(evt);
159 observer.next(evt);
160 } catch (e) {
160 } catch (e) {
161 this.onObserverException(e);
161 this.onObserverException(e);
162 }
162 }
163 }
163 }
164
164
165 this._notify(guard);
165 this._notify(guard);
166 }
166 }
167
167
168 protected _notifyError(e: any) {
168 protected _notifyError(e: any) {
169 let guard = (observer: IObserver<T>) => {
169 let guard = (observer: IObserver<T>) => {
170 try {
170 try {
171 observer.error(e);
171 observer.error(e);
172 } catch (e) {
172 } catch (e) {
173 this.onObserverException(e);
173 this.onObserverException(e);
174 }
174 }
175 }
175 }
176
176
177 this._notify(guard);
177 this._notify(guard);
178 this._observers = [];
178 this._observers = [];
179 }
179 }
180
180
181 protected _notifyCompleted() {
181 protected _notifyCompleted() {
182 let guard = (observer: IObserver<T>) => {
182 let guard = (observer: IObserver<T>) => {
183 try {
183 try {
184 observer.complete();
184 observer.complete();
185 } catch (e) {
185 } catch (e) {
186 this.onObserverException(e);
186 this.onObserverException(e);
187 }
187 }
188 }
188 }
189
189
190 this._notify(guard);
190 this._notify(guard);
191 this._observers = [];
191 this._observers = [];
192 }
192 }
193 } No newline at end of file
193 }
General Comments 0
You need to be logged in to leave comments. Login now