@fbltd/async 1.0.25 → 1.0.27

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/README.md CHANGED
@@ -36,7 +36,6 @@ There is no any management of passed data for resolving.
36
36
  Returned promise is usual ES promise so it is impossible to fulfill promise twice.
37
37
 
38
38
  ### DependencyStream
39
- #### core
40
39
  Implementation of reactive model leveraging native JavaScript async features like
41
40
  Promises, (async) iterators and generators.
42
41
  The version is 0.0.x so keep it in mind
@@ -75,14 +74,17 @@ setInterval(() => {
75
74
  ##### reaction
76
75
  The most powerful util among all stream utils.
77
76
  Function is watching only for actual dependencies and does not react
78
- for dependencies that do not affect result value:
77
+ for dependencies that do not affect result value. Since the reaction
78
+ provides dependency instance, of course, there is a function result caching:
79
79
  ```typescript
80
80
  let isDep1Ready = new Dependency(false);
81
81
  let isDep2Ready = new Dependency(false);
82
82
  let counter = new Dependency(0);
83
83
 
84
- // function that implicityly uses dependency instances
85
- let cachedFunction = () => {
84
+ // function that uses dependency instances
85
+ let watchFn = () => {
86
+ // Take a look at IF condition -
87
+ // value can be changed only if dep1 and dep2 is ready
86
88
  if (isDep1Ready.value && isDep2Ready.value) {
87
89
  return counter.value;
88
90
  }
@@ -90,16 +92,12 @@ let cachedFunction = () => {
90
92
  }
91
93
 
92
94
  async function subscribe() {
93
- for await (const value of reaction(cachedFunction)) {
95
+ for await (const value of reaction(watchFn)) {
94
96
  reactionFn();
95
97
  }
96
98
  exitFn();
97
99
  }
98
100
  ```
99
- The reaction is declared deprecated because a return value caching does not
100
- use optimal strategy. Moreover, ideally, reaction should give back a
101
- dependency instance or something like it, that can provide an ability
102
- to be an observable for another reaction.
103
101
 
104
102
  #### Framework integrations
105
103
  ##### React
@@ -0,0 +1,10 @@
1
+ import { Dependency } from "./dependency.js";
2
+ import { reaction } from "./stream-utils/index.js";
3
+ export class DepFactory {
4
+ static ofValue(value, config) {
5
+ return new Dependency(value, config);
6
+ }
7
+ static ofReaction(fn, config) {
8
+ return reaction(fn, config);
9
+ }
10
+ }
@@ -1,6 +1,7 @@
1
1
  import { PromiseConfiguration } from "../promise-configuration.js";
2
2
  import { baseComparer } from "./utils.js";
3
3
  import { collectDep } from "./global.js";
4
+ import { symAI } from "../constants.js";
4
5
  export class Dependency {
5
6
  _value;
6
7
  reactionPromise;
@@ -36,7 +37,7 @@ export class Dependency {
36
37
  get done() {
37
38
  return this.abortPromise.isFulfilled;
38
39
  }
39
- [Symbol.asyncIterator](thisStreamConfig = {}) {
40
+ [symAI](thisStreamConfig = {}) {
40
41
  const externalPromises = [];
41
42
  let firstPromise;
42
43
  const withReactionOnSubscribe = this.config.withReactionOnSubscribe || thisStreamConfig.withReactionOnSubscribe;
@@ -110,6 +111,9 @@ export class Dependency {
110
111
  }
111
112
  };
112
113
  }
114
+ get disposePromise() {
115
+ return this.abortPromise.promise;
116
+ }
113
117
  dispose() {
114
118
  this.abortPromise.resolve();
115
119
  this.reactionPromise = undefined;
@@ -1,4 +1,5 @@
1
1
  export * from "./dependency.js";
2
2
  export * from "./dependency.stream.js";
3
+ export * from "./dep.factory.js";
3
4
  export * from "./stream-utils/index.js";
4
5
  export * from "./integrations/index.js";
@@ -1,4 +1,3 @@
1
- import { symAI } from "../../constants.js";
2
1
  import { PromiseConfiguration } from "../../promise-configuration.js";
3
2
  /**
4
3
  * @internal
@@ -7,13 +6,14 @@ export const StreamFinishError = new Error("Stream is done");
7
6
  export function next(dep) {
8
7
  const disposePromise = new PromiseConfiguration();
9
8
  const resultPromise = new PromiseConfiguration();
10
- dep[symAI]({ externalDispose: disposePromise })
11
- .next()
9
+ Promise.race([dep.next(), disposePromise.promise])
12
10
  .then((res) => {
13
- if (res.done)
11
+ if (dep.done || disposePromise.isFulfilled) {
14
12
  resultPromise.reject(StreamFinishError);
15
- else
16
- resultPromise.resolve(res.value);
13
+ }
14
+ else {
15
+ resultPromise.resolve(dep.value);
16
+ }
17
17
  });
18
18
  return {
19
19
  promise: resultPromise.promise,
@@ -1,35 +1,44 @@
1
1
  import { runFnWithDepCollection } from "../global.js";
2
- /**
3
- * @deprecated
4
- */
5
- export function reaction(fn) {
6
- return {
7
- [Symbol.asyncIterator]: () => {
8
- let { result, deps } = runFnWithDepCollection(fn);
9
- let depsArray;
10
- let beforeValues;
11
- let obj = {
12
- next: async () => {
13
- depsArray = Array.from(deps);
14
- beforeValues = depsArray.map(dep => dep.value);
15
- await Promise.race(depsArray.map(dep => dep.next()));
16
- let shouldRun = depsArray.some((dep, i) => dep.value !== beforeValues[i]);
17
- if (shouldRun) {
18
- ({ result, deps } = runFnWithDepCollection(fn));
19
- return { done: false, value: result };
20
- }
21
- else {
22
- for (let dep of deps) {
23
- if (dep.done)
24
- deps.delete(dep);
25
- }
26
- if (!deps.size)
2
+ import { Dependency } from "../dependency.js";
3
+ import { symAI } from "../../constants.js";
4
+ export function reaction(fn, config) {
5
+ let { result, deps } = runFnWithDepCollection(fn);
6
+ const dep = new Dependency(result, config);
7
+ async function subscribe() {
8
+ const stream = { [symAI]: () => {
9
+ let depsArray;
10
+ let beforeValues;
11
+ let obj = {
12
+ next: async () => {
13
+ depsArray = Array.from(deps);
14
+ beforeValues = depsArray.map(dep => dep.value);
15
+ const promises = depsArray.map(dep => dep.next());
16
+ promises.push(dep.disposePromise);
17
+ await Promise.race(depsArray.map(dep => dep.next()));
18
+ if (dep.done)
27
19
  return { done: true };
28
- return obj.next();
20
+ let shouldRun = depsArray.some((dep, i) => dep.value !== beforeValues[i]);
21
+ if (shouldRun) {
22
+ ({ result, deps } = runFnWithDepCollection(fn));
23
+ return { done: false, value: result };
24
+ }
25
+ else {
26
+ for (let dep of deps) {
27
+ if (dep.done)
28
+ deps.delete(dep);
29
+ }
30
+ if (!deps.size)
31
+ return { done: true };
32
+ return obj.next();
33
+ }
29
34
  }
30
- }
31
- };
32
- return obj;
35
+ };
36
+ return obj;
37
+ } };
38
+ for await (let value of stream) {
39
+ dep.value = value;
33
40
  }
34
- };
41
+ }
42
+ subscribe().then(() => dep.dispose());
43
+ return dep;
35
44
  }
@@ -0,0 +1,6 @@
1
+ import { Dependency } from "./dependency.ts";
2
+ import { IAllStreamConfig } from "./contracts.ts";
3
+ export declare abstract class DepFactory {
4
+ static ofValue<T>(value: T, config?: Partial<IAllStreamConfig<T>>): Dependency<T>;
5
+ static ofReaction<T>(fn: () => T, config?: Partial<IAllStreamConfig<T>>): Dependency<T>;
6
+ }
@@ -1,4 +1,5 @@
1
1
  import { IAllStreamConfig, IStreamIterator, IThisStreamConfig } from "./contracts.ts";
2
+ import { symAI } from "../constants.ts";
2
3
  export declare class Dependency<T = any> {
3
4
  private _value;
4
5
  private reactionPromise;
@@ -9,7 +10,7 @@ export declare class Dependency<T = any> {
9
10
  set value(v: T);
10
11
  get value(): T;
11
12
  get done(): boolean;
12
- [Symbol.asyncIterator](this: Dependency<T>, thisStreamConfig?: IThisStreamConfig): IStreamIterator<T>;
13
+ [symAI](this: Dependency<T>, thisStreamConfig?: IThisStreamConfig): IStreamIterator<T>;
13
14
  /**
14
15
  * One race of value change and dependency dispose
15
16
  * for all subscribers
@@ -26,5 +27,6 @@ export declare class Dependency<T = any> {
26
27
  done: boolean;
27
28
  readonly value: T;
28
29
  }>;
30
+ get disposePromise(): Promise<void>;
29
31
  dispose(this: Dependency<T>): void;
30
32
  }
@@ -1,4 +1,5 @@
1
1
  export * from './dependency.ts';
2
2
  export * from './dependency.stream.ts';
3
+ export * from './dep.factory.ts';
3
4
  export * from './stream-utils/index.ts';
4
5
  export * from './integrations/index.ts';
@@ -1,14 +1,3 @@
1
- /**
2
- * @deprecated
3
- */
4
- export declare function reaction<T>(fn: () => T): {
5
- [Symbol.asyncIterator]: () => {
6
- next: () => Promise<{
7
- done: true;
8
- value?: never;
9
- } | {
10
- done: false;
11
- value: T;
12
- }>;
13
- };
14
- };
1
+ import { Dependency } from "../dependency.ts";
2
+ import { IAllStreamConfig } from "../contracts.js";
3
+ export declare function reaction<T>(fn: () => T, config?: Partial<IAllStreamConfig<T>>): Dependency<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fbltd/async",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "Miscellaneous async utils",
5
5
  "homepage": "https://github.com/GlennMiller1991/async",
6
6
  "type": "module",