evg_observable 2.15.8 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +410 -0
- package/README.md +204 -67
- package/package.json +1 -1
- package/repo/evg_observable.js +1 -1
- package/src/outLib/AbstractSwitchCase.d.ts +2 -2
- package/src/outLib/AbstractSwitchCase.js +3 -3
- package/src/outLib/FilterCollection.d.ts +3 -3
- package/src/outLib/FilterCollection.js +4 -4
- package/src/outLib/Observable.d.ts +2 -1
- package/src/outLib/Observable.js +12 -1
- package/src/outLib/OrderedObservable.d.ts +2 -2
- package/src/outLib/OrderedObservable.js +2 -2
- package/src/outLib/OrderedSubscribeObject.d.ts +1 -1
- package/src/outLib/OrderedSubscribeObject.js +2 -2
- package/src/outLib/Pipe.d.ts +10 -8
- package/src/outLib/Pipe.js +14 -8
- package/src/outLib/SubscribeObject.d.ts +4 -1
- package/src/outLib/SubscribeObject.js +76 -6
- package/src/outLib/Types.d.ts +37 -24
- package/BREAKING_CHANGES.md +0 -70
|
@@ -6,5 +6,5 @@ export declare class OrderedSubscribeObject<T> extends SubscribeObject<T> implem
|
|
|
6
6
|
get order(): number;
|
|
7
7
|
set order(value: number);
|
|
8
8
|
subscribe(observer: IListener<T> | ISetObservableValue, errorHandler?: IErrorCallback): IOrderedSubscriptionLike;
|
|
9
|
-
|
|
9
|
+
once(): IOrderedSubscribe<T>;
|
|
10
10
|
}
|
|
@@ -22,8 +22,8 @@ class OrderedSubscribeObject extends SubscribeObject_1.SubscribeObject {
|
|
|
22
22
|
super.subscribe(observer, errorHandler);
|
|
23
23
|
return this;
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
return super.
|
|
25
|
+
once() {
|
|
26
|
+
return super.once();
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
exports.OrderedSubscribeObject = OrderedSubscribeObject;
|
package/src/outLib/Pipe.d.ts
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import { ICallback, IChainCallback, IErrorCallback, IListener, IPipeCase, IPipePayload, ISetObservableValue, ISetup, ISubscribe, ISubscriptionLike } from "./Types";
|
|
1
|
+
import { ICallback, IChainCallback, IErrorCallback, IGroupSubscription, IListener, IPipeCase, IPipePayload, ISetObservableValue, ISetup, ISubscribe, ISubscriptionLike } from "./Types";
|
|
2
2
|
import { SwitchCase } from "./AbstractSwitchCase";
|
|
3
3
|
export declare abstract class Pipe<T> implements ISubscribe<T> {
|
|
4
4
|
chain: IChainCallback[];
|
|
5
5
|
flow: IPipePayload;
|
|
6
6
|
abstract subscribe(listener: IListener<T> | ISetObservableValue, errorHandler?: IErrorCallback): ISubscriptionLike | undefined;
|
|
7
7
|
private push;
|
|
8
|
-
|
|
8
|
+
once(): ISubscribe<T>;
|
|
9
9
|
unsubscribeBy(condition: ICallback<T>): ISetup<T>;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
and(condition: ICallback<T>): ISetup<T>;
|
|
11
|
+
allOf(conditions: ICallback<any>[]): ISetup<T>;
|
|
12
|
+
choice(): PipeSwitchCase<T>;
|
|
13
|
+
map<K>(condition: ICallback<T>): ISetup<K>;
|
|
14
|
+
toJson(): ISetup<string>;
|
|
15
|
+
fromJson<K>(): ISetup<K>;
|
|
16
|
+
group(): IGroupSubscription<T>;
|
|
16
17
|
processChain(listener: IListener<T>): void;
|
|
17
18
|
}
|
|
18
19
|
export declare class PipeSwitchCase<T> extends SwitchCase<T, Pipe<T>, IPipeCase<T>> implements ISubscribe<T> {
|
|
19
20
|
subscribe(listener: IListener<T> | ISetObservableValue, errorHandler?: IErrorCallback): ISubscriptionLike | undefined;
|
|
21
|
+
group(): IGroupSubscription<T>;
|
|
20
22
|
}
|
package/src/outLib/Pipe.js
CHANGED
|
@@ -9,7 +9,7 @@ class Pipe {
|
|
|
9
9
|
this.chain.push(callback);
|
|
10
10
|
return this;
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
once() {
|
|
13
13
|
return this.push((data) => {
|
|
14
14
|
this.listener(data.payload);
|
|
15
15
|
data.isUnsubscribe = true;
|
|
@@ -22,37 +22,40 @@ class Pipe {
|
|
|
22
22
|
data.isUnsubscribe = true;
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
and(condition) {
|
|
26
26
|
return this.push((data) => condition(data.payload) && (data.isAvailable = true));
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
allOf(conditions) {
|
|
29
29
|
if (!Array.isArray(conditions))
|
|
30
30
|
return this;
|
|
31
31
|
for (let i = 0; i < conditions.length; i++)
|
|
32
|
-
this.
|
|
32
|
+
this.and(conditions[i]);
|
|
33
33
|
return this;
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
choice() {
|
|
36
36
|
return new PipeSwitchCase(this);
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
map(condition) {
|
|
39
39
|
return this.push((data) => {
|
|
40
40
|
data.payload = condition(data.payload);
|
|
41
41
|
data.isAvailable = true;
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
|
-
|
|
44
|
+
toJson() {
|
|
45
45
|
return this.push((data) => {
|
|
46
46
|
data.payload = JSON.stringify(data.payload);
|
|
47
47
|
data.isAvailable = true;
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
|
-
|
|
50
|
+
fromJson() {
|
|
51
51
|
return this.push((data) => {
|
|
52
52
|
data.payload = JSON.parse(data.payload);
|
|
53
53
|
data.isAvailable = true;
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
|
+
group() {
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
56
59
|
processChain(listener) {
|
|
57
60
|
const chain = this.chain;
|
|
58
61
|
const data = this.flow;
|
|
@@ -76,5 +79,8 @@ class PipeSwitchCase extends AbstractSwitchCase_1.SwitchCase {
|
|
|
76
79
|
subscribe(listener, errorHandler) {
|
|
77
80
|
return this.pipe.subscribe(listener, errorHandler);
|
|
78
81
|
}
|
|
82
|
+
group() {
|
|
83
|
+
return this.pipe;
|
|
84
|
+
}
|
|
79
85
|
}
|
|
80
86
|
exports.PipeSwitchCase = PipeSwitchCase;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IErrorCallback, IListener, IObserver, ISubscribeGroup, ISubscribeObject, ISubscriptionLike } from "./Types";
|
|
1
|
+
import { IErrorCallback, IGroupSubscription, IListener, IObserver, ISubscribeGroup, ISubscribeObject, ISubscriptionLike } from "./Types";
|
|
2
2
|
import { Pipe } from "./Pipe";
|
|
3
3
|
export declare class SubscribeObject<T> extends Pipe<T> implements ISubscribeObject<T> {
|
|
4
4
|
observer: IObserver<T> | undefined;
|
|
@@ -7,8 +7,11 @@ export declare class SubscribeObject<T> extends Pipe<T> implements ISubscribeObj
|
|
|
7
7
|
_order: number;
|
|
8
8
|
paused: boolean;
|
|
9
9
|
piped: boolean;
|
|
10
|
+
listeners?: IListener<T>[];
|
|
11
|
+
errorHandlers?: IErrorCallback[];
|
|
10
12
|
constructor(observable?: IObserver<T>, isPipe?: boolean);
|
|
11
13
|
subscribe(observer: ISubscribeGroup<T>, errorHandler?: IErrorCallback): ISubscriptionLike;
|
|
14
|
+
add(listener: IListener<T> | IListener<T>[], errorHandler?: IErrorCallback | IErrorCallback[]): IGroupSubscription<T>;
|
|
12
15
|
unsubscribe(): void;
|
|
13
16
|
send(value: T): void;
|
|
14
17
|
resume(): void;
|
|
@@ -12,6 +12,8 @@ class SubscribeObject extends Pipe_1.Pipe {
|
|
|
12
12
|
_order = 0;
|
|
13
13
|
paused = false;
|
|
14
14
|
piped = false;
|
|
15
|
+
listeners;
|
|
16
|
+
errorHandlers;
|
|
15
17
|
constructor(observable, isPipe) {
|
|
16
18
|
super();
|
|
17
19
|
this.observer = observable;
|
|
@@ -22,6 +24,29 @@ class SubscribeObject extends Pipe_1.Pipe {
|
|
|
22
24
|
errorHandler && (this.errorHandler = errorHandler);
|
|
23
25
|
return this;
|
|
24
26
|
}
|
|
27
|
+
add(listener, errorHandler) {
|
|
28
|
+
if (!this.listeners) {
|
|
29
|
+
this.listeners = [];
|
|
30
|
+
this.errorHandlers = [];
|
|
31
|
+
}
|
|
32
|
+
if (Array.isArray(listener)) {
|
|
33
|
+
for (let i = 0; i < listener.length; i++) {
|
|
34
|
+
this.listeners.push(listener[i]);
|
|
35
|
+
const handler = (errorHandler && Array.isArray(errorHandler))
|
|
36
|
+
? (errorHandler[i] ?? this.errorHandler)
|
|
37
|
+
: (errorHandler || this.errorHandler);
|
|
38
|
+
this.errorHandlers.push(handler);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this.listeners.push(listener);
|
|
43
|
+
const handler = (errorHandler && !Array.isArray(errorHandler))
|
|
44
|
+
? errorHandler
|
|
45
|
+
: this.errorHandler;
|
|
46
|
+
this.errorHandlers.push(handler);
|
|
47
|
+
}
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
25
50
|
unsubscribe() {
|
|
26
51
|
if (!this.observer)
|
|
27
52
|
return;
|
|
@@ -32,25 +57,70 @@ class SubscribeObject extends Pipe_1.Pipe {
|
|
|
32
57
|
}
|
|
33
58
|
send(value) {
|
|
34
59
|
const listener = this.listener;
|
|
35
|
-
|
|
60
|
+
const hasGroupListeners = this.listeners && this.listeners.length > 0;
|
|
61
|
+
if (!listener && !hasGroupListeners) {
|
|
36
62
|
this.unsubscribe();
|
|
37
63
|
return;
|
|
38
64
|
}
|
|
39
65
|
if (!this.observer || this.paused)
|
|
40
66
|
return;
|
|
41
67
|
if (!this.piped) {
|
|
42
|
-
|
|
43
|
-
|
|
68
|
+
if (listener) {
|
|
69
|
+
try {
|
|
70
|
+
listener(value);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
this.errorHandler(value, err);
|
|
74
|
+
}
|
|
44
75
|
}
|
|
45
|
-
|
|
46
|
-
this.
|
|
76
|
+
if (hasGroupListeners) {
|
|
77
|
+
for (let i = 0; i < this.listeners.length; i++) {
|
|
78
|
+
try {
|
|
79
|
+
this.listeners[i](value);
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
this.errorHandlers[i](value, err);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
47
85
|
}
|
|
48
86
|
return;
|
|
49
87
|
}
|
|
50
88
|
try {
|
|
51
89
|
this.flow.payload = value;
|
|
52
90
|
this.flow.isBreak = false;
|
|
53
|
-
|
|
91
|
+
if (listener) {
|
|
92
|
+
this.processChain(listener);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const chain = this.chain;
|
|
96
|
+
const data = this.flow;
|
|
97
|
+
const len = chain.length;
|
|
98
|
+
data.isAvailable = len === 0;
|
|
99
|
+
for (let i = 0; i < len; i++) {
|
|
100
|
+
data.isUnsubscribe = false;
|
|
101
|
+
data.isAvailable = false;
|
|
102
|
+
chain[i](data);
|
|
103
|
+
if (data.isUnsubscribe) {
|
|
104
|
+
this.unsubscribe();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
if (!data.isAvailable)
|
|
108
|
+
return;
|
|
109
|
+
if (data.isBreak)
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (hasGroupListeners) {
|
|
114
|
+
const processedValue = this.flow.payload;
|
|
115
|
+
for (let i = 0; i < this.listeners.length; i++) {
|
|
116
|
+
try {
|
|
117
|
+
this.listeners[i](processedValue);
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
this.errorHandlers[i](processedValue, err);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
54
124
|
}
|
|
55
125
|
catch (err) {
|
|
56
126
|
this.errorHandler(value, err);
|
package/src/outLib/Types.d.ts
CHANGED
|
@@ -14,16 +14,22 @@ export type IOrder = {
|
|
|
14
14
|
order: number;
|
|
15
15
|
};
|
|
16
16
|
export type ISwitch<T> = {
|
|
17
|
-
|
|
17
|
+
choice(): PipeSwitchCase<T>;
|
|
18
18
|
};
|
|
19
19
|
export type IOrderedSwitch<T> = {
|
|
20
|
-
|
|
20
|
+
choice(): PipeSwitchCase<T>;
|
|
21
|
+
};
|
|
22
|
+
export type IGroup<T> = {
|
|
23
|
+
group(): IGroupSubscription<T>;
|
|
24
|
+
};
|
|
25
|
+
export type IOrderedGroup<T> = {
|
|
26
|
+
group(): IGroupSubscription<T>;
|
|
21
27
|
};
|
|
22
28
|
export type IOnce<T> = {
|
|
23
|
-
|
|
29
|
+
once(): ISubscribe<T>;
|
|
24
30
|
};
|
|
25
31
|
export type IOrderedOnce<T> = {
|
|
26
|
-
|
|
32
|
+
once(): IOrderedSubscribe<T>;
|
|
27
33
|
};
|
|
28
34
|
export type ISetObservableValue = {
|
|
29
35
|
next(value: any): void;
|
|
@@ -31,8 +37,11 @@ export type ISetObservableValue = {
|
|
|
31
37
|
export type ISubscriptionLike = {
|
|
32
38
|
unsubscribe(): void;
|
|
33
39
|
};
|
|
34
|
-
export type
|
|
35
|
-
|
|
40
|
+
export type IGroupSubscription<T> = ISubscriptionLike & {
|
|
41
|
+
add(listener: IListener<T> | IListener<T>[], errorHandler?: IErrorCallback | IErrorCallback[]): IGroupSubscription<T>;
|
|
42
|
+
};
|
|
43
|
+
export type ISetup<T> = IUnsubscribeByPositive<T> & IEmitByPositive<T> & IOnce<T> & ISwitch<T> & ITransform<T> & ISerialisation & IGroup<T> & ISubscribe<T>;
|
|
44
|
+
export type IOrderedSetup<T> = IOrderedUnsubscribeByPositive<T> & IOrderedEmitByPositive<T> & IOrderedOnce<T> & IOrderedSwitch<T> & IOrderedTransform<T> & IOrderedSerialisation & IOrderedGroup<T> & IOrderedSubscribe<T>;
|
|
36
45
|
export type ISubscribeObject<T> = ISubscriptionLike & IPause & IOrder & ISend<T> & ISetup<T>;
|
|
37
46
|
export type ISubscribeCounter = {
|
|
38
47
|
size(): number;
|
|
@@ -48,7 +57,10 @@ export type IObserver<T> = ISetObservableValue & ISubscriber<T> & IDestroy & ISu
|
|
|
48
57
|
enable(): void;
|
|
49
58
|
};
|
|
50
59
|
export type IStream<T> = {
|
|
51
|
-
|
|
60
|
+
of(value: T[]): void;
|
|
61
|
+
};
|
|
62
|
+
export type IObjectStream<K extends string | number | symbol, V> = {
|
|
63
|
+
in(value: Record<K, V>): void;
|
|
52
64
|
};
|
|
53
65
|
export type IPause = {
|
|
54
66
|
pause(): void;
|
|
@@ -82,26 +94,26 @@ export type IOrderedEmitByNegative<T> = {
|
|
|
82
94
|
emitByNegative(condition: ICallback<T>): IOrderedSetup<T>;
|
|
83
95
|
};
|
|
84
96
|
export type IEmitByPositive<T> = {
|
|
85
|
-
|
|
86
|
-
|
|
97
|
+
and(condition: ICallback<T>): ISetup<T>;
|
|
98
|
+
allOf(conditions: ICallback<T>[]): ISetup<T>;
|
|
87
99
|
};
|
|
88
100
|
export type ITransform<T> = {
|
|
89
|
-
|
|
101
|
+
map<K>(condition: ICallback<T>): ISetup<K>;
|
|
90
102
|
};
|
|
91
103
|
export type ISerialisation = {
|
|
92
|
-
|
|
93
|
-
|
|
104
|
+
toJson(): ISetup<string>;
|
|
105
|
+
fromJson<K>(): ISetup<K>;
|
|
94
106
|
};
|
|
95
107
|
export type IOrderedEmitByPositive<T> = {
|
|
96
|
-
|
|
97
|
-
|
|
108
|
+
and(condition: ICallback<any>): ISetup<T>;
|
|
109
|
+
allOf(conditions: ICallback<any>[]): ISetup<T>;
|
|
98
110
|
};
|
|
99
111
|
export type IOrderedTransform<T> = {
|
|
100
|
-
|
|
112
|
+
map<K>(condition: ICallback<T>): ISetup<K>;
|
|
101
113
|
};
|
|
102
114
|
export type IOrderedSerialisation = {
|
|
103
|
-
|
|
104
|
-
|
|
115
|
+
toJson(): ISetup<string>;
|
|
116
|
+
fromJson<K>(): ISetup<K>;
|
|
105
117
|
};
|
|
106
118
|
export type IEmitMatchCondition<T> = {
|
|
107
119
|
emitMatch(condition: ICallback<any>): ISetup<T>;
|
|
@@ -133,8 +145,9 @@ export type IPipePayload = {
|
|
|
133
145
|
};
|
|
134
146
|
export type IChainCallback = (data: IPipePayload) => void;
|
|
135
147
|
export type IPipeCase<T> = ISubscribe<T> & {
|
|
136
|
-
|
|
137
|
-
|
|
148
|
+
or(condition: ICallback<any>): IPipeCase<T> & ISubscribe<T>;
|
|
149
|
+
anyOf(conditions: ICallback<any>[]): IPipeCase<T> & ISubscribe<T>;
|
|
150
|
+
group(): IGroupSubscription<T>;
|
|
138
151
|
};
|
|
139
152
|
export type ICombinedSubscriber<T> = IListener<T> | ISetObservableValue;
|
|
140
153
|
export type ISubscribeGroup<T> = ICombinedSubscriber<T> | ICombinedSubscriber<T>[];
|
|
@@ -143,15 +156,15 @@ export type IAddFilter<T> = {
|
|
|
143
156
|
};
|
|
144
157
|
export type IFilterSetup<T> = IFilter<T> & IFilterSwitch<T>;
|
|
145
158
|
export type IFilter<T> = {
|
|
146
|
-
|
|
147
|
-
|
|
159
|
+
and(condition: ICallback<any>): IFilterSetup<T>;
|
|
160
|
+
allOf(conditions: ICallback<any>[]): IFilterSetup<T>;
|
|
148
161
|
};
|
|
149
162
|
export type IFilterSwitch<T> = {
|
|
150
|
-
|
|
163
|
+
choice(): FilterSwitchCase<T>;
|
|
151
164
|
};
|
|
152
165
|
export type IFilterCase<T> = {
|
|
153
|
-
|
|
154
|
-
|
|
166
|
+
or(condition: ICallback<any>): IFilterCase<T>;
|
|
167
|
+
anyOf(conditions: ICallback<any>[]): IFilterCase<T>;
|
|
155
168
|
};
|
|
156
169
|
export type IFilterPayload = {
|
|
157
170
|
isBreak: boolean;
|
package/BREAKING_CHANGES.md
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
# Breaking Changes - Performance Optimizations Branch
|
|
2
|
-
|
|
3
|
-
## Version 2.15.0
|
|
4
|
-
|
|
5
|
-
### Internal Field Renaming
|
|
6
|
-
|
|
7
|
-
**Affected field:** `value` renamed to `_value`
|
|
8
|
-
|
|
9
|
-
The internal field storing the current observable value has been renamed from `value` to `_value` to follow TypeScript conventions for protected/private members.
|
|
10
|
-
|
|
11
|
-
**Before:**
|
|
12
|
-
```typescript
|
|
13
|
-
export class Observable<T> {
|
|
14
|
-
constructor(private value: T) {}
|
|
15
|
-
}
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
**After:**
|
|
19
|
-
```typescript
|
|
20
|
-
export class Observable<T> {
|
|
21
|
-
protected _value: T;
|
|
22
|
-
constructor(value: T) {
|
|
23
|
-
this._value = value;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
**Migration:**
|
|
29
|
-
- If you were extending `Observable` and accessing `this.value`, change to `this._value`
|
|
30
|
-
- Use the public `getValue()` method for reading the current value (recommended)
|
|
31
|
-
|
|
32
|
-
### Visibility Changes
|
|
33
|
-
|
|
34
|
-
The following fields changed from `private` to `protected` to enable better inheritance:
|
|
35
|
-
|
|
36
|
-
| Field | Before | After |
|
|
37
|
-
|-------|--------|-------|
|
|
38
|
-
| `enabled` | private | protected |
|
|
39
|
-
| `filters` | private | protected |
|
|
40
|
-
| `_value` (formerly `value`) | private | protected |
|
|
41
|
-
|
|
42
|
-
**Impact:** This is not a breaking change for most users, but allows subclasses to access these fields.
|
|
43
|
-
|
|
44
|
-
### Recommended Migration Path
|
|
45
|
-
|
|
46
|
-
Instead of accessing internal fields directly, use the public API:
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
// Instead of:
|
|
50
|
-
// @ts-ignore
|
|
51
|
-
const val = observable._value;
|
|
52
|
-
|
|
53
|
-
// Use:
|
|
54
|
-
const val = observable.getValue();
|
|
55
|
-
|
|
56
|
-
// Instead of:
|
|
57
|
-
// @ts-ignore
|
|
58
|
-
const count = observable.subs.length;
|
|
59
|
-
|
|
60
|
-
// Use:
|
|
61
|
-
const count = observable.size();
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### New Behavior
|
|
65
|
-
|
|
66
|
-
1. **`destroy()` now uses `Promise.resolve()`** instead of `setInterval()` for async cleanup when called during emission
|
|
67
|
-
2. **`unsubscribeAll()` is now safe to call during `next()`** - uses deferred cleanup mechanism
|
|
68
|
-
3. **Early exit optimization** - `next()` returns immediately if there are no subscribers
|
|
69
|
-
|
|
70
|
-
These behavioral changes improve performance and memory management but should not require code changes.
|