From d9ed402d271aa57931dace6900d9a9eaa8c8838f Mon Sep 17 00:00:00 2001 From: Gilad S Date: Wed, 22 Nov 2023 03:09:58 +0200 Subject: [PATCH] docs: update `README.md` --- .run/test.run.xml | 12 +++ README.md | 207 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 .run/test.run.xml diff --git a/.run/test.run.xml b/.run/test.run.xml new file mode 100644 index 0000000..62b87ea --- /dev/null +++ b/.run/test.run.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 94d7e37..60c9f2c 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ npm install --save lifecycle-utils Calling `withLock` with the same `scope` and `key` will ensure that the callback inside cannot run in parallel to other calls with the same `scope` and `key`. ```typescript -import { withLock } from "lifecycle-utils"; +import {withLock} from "lifecycle-utils"; const scope = {}; // can be reference to any object you like const startTime = Date.now(); @@ -53,7 +53,7 @@ console.log(res); // [42, 42, 42] Check whether a lock is currently active for the given `scope` and `key`. ```typescript -import { isLockActive } from "lifecycle-utils"; +import {isLockActive} from "lifecycle-utils"; const scope = {}; // can be reference to any object you like @@ -65,7 +65,7 @@ console.log(res); // false Acquire a lock for the given `scope` and `key`. ```typescript -import { acquireLock } from "lifecycle-utils"; +import {acquireLock} from "lifecycle-utils"; const scope = {}; // can be reference to any object you like @@ -77,6 +77,207 @@ console.log("lock acquired"); activeLock.dispose(); ``` +### `EventRelay` +A simple event relay. + +Create a listener with `createListener` and dispatch events with `dispatchEvent`. + +For each supported event type, create a new instance of `EventRelay` and expose it as a property. + +For example, this code: +```ts +import {EventRelay} from "lifecycle-utils"; + +class MyClass { + public readonly onSomethingHappened = new EventRelay(); + + public doSomething(whatToDo: string) { + this.onSomethingHappened.dispatchEvent(whatToDo); + console.log("Done notifying listeners"); + } +} + +const myClass = new MyClass(); +myClass.onSomethingHappened.createListener((whatHappened) => { + console.log(`Something happened: ${whatHappened}`); +}); +myClass.doSomething("eat a cookie"); +``` + +Will print this: +``` +Something happened: eat a cookie +Done notifying listeners +``` + +### `DisposeAggregator` +`DisposeAggregator` is a utility class that allows you to add multiple items and then dispose them all at once. + +You can add a function to call, an object with a `dispose` method, or an object with a `Symbol.dispose` method. + +To dispose all the items, call `dispose` or use the `Symbol.dispose` symbol. + +```typescript +import {DisposeAggregator, EventRelay} from "lifecycle-utils"; + +const disposeAggregator = new DisposeAggregator(); + +const eventRelay = new EventRelay(); +disposeAggregator.add(eventRelay); + +const eventRelay2 = disposeAggregator.add(new EventRelay()); + +disposeAggregator.dispose(); +console.log(eventRelay.disposed === true); // true +console.log(eventRelay2.disposed === true); // true +``` + +### `AsyncDisposeAggregator` +`AsyncDisposeAggregator` is a utility class that allows you to add multiple items and then dispose them all at once. + +The items are disposed one by one in the order they were added. + +You can add a function to call, an object with a `dispose` method, an object with a `Symbol.dispose` method, + +an object with a `Symbol.asyncDispose` method, or a Promise that resolves to one of the previous types. + +To dispose all the items, call `dispose` or use the `Symbol.asyncDispose` symbol. + +The difference between `AsyncDisposeAggregator` and `DisposeAggregator` is that `AsyncDisposeAggregator` can dispose async targets. + +```typescript +import {AsyncDisposeAggregator, EventRelay} from "lifecycle-utils"; + +const disposeAggregator = new AsyncDisposeAggregator(); + +const eventRelay = new EventRelay(); +disposeAggregator.add(eventRelay); + +disposeAggregator.add(async () => { + await new Promise(resolve => setTimeout(resolve, 0)); + // do some async work +}); + +disposeAggregator.dispose(); +``` + +### `LongTimeout` +A timeout that can be set to a delay longer than the maximum timeout delay supported by a regular `setTimeout`. + +```typescript +import {LongTimeout} from "lifecycle-utils"; + +const month = 1000 * 60 * 60 * 24 * 7 * 30; + +const timeout = new LongTimeout(() => { + console.log("timeout"); +}, month); + +// to clear the timeout, call dispose +// timeout.dispose(); +``` + +### `setLongTimeout` +Sets a timeout that can also be set to a delay longer than the maximum timeout delay supported by a regular `setTimeout`. + +You can use `clearLongTimeout` to clear the timeout. + +```typescript +import {setLongTimeout, clearLongTimeout} from "lifecycle-utils"; + +const month = 1000 * 60 * 60 * 24 * 7 * 30; + +const timeout = setLongTimeout(() => { + console.log("timeout"); +}, month); + +// to clear the timeout, call clearLongTimeout +// clearLongTimeout(timeout); +``` + +### `clearLongTimeout` +Clears a timeout that was set with `setLongTimeout`. + +You can also clear a regular timeout with this function. + +```typescript +import {setLongTimeout, clearLongTimeout} from "lifecycle-utils"; + +const month = 1000 * 60 * 60 * 24 * 7 * 30; + +const timeout = setLongTimeout(() => { + console.log("timeout"); +}, month); +const timeout2 = setTimeout(() => { + console.log("timeout2"); +}, 1000 * 60); + +clearLongTimeout(timeout); +clearLongTimeout(timeout2); +``` + +### `State` +`State` is a utility class that allows you to hold a value and notify listeners when the value changes. + +```typescript +import {State} from "lifecycle-utils"; + +const valueState = new State(6); + +const eventHandle = valueState.createChangeListener((newValue, previousValue) => { + console.log("new value:", newValue); + console.log("previous value:", previousValue); +}); + +valueState.state = 7; + +// after a microtask, the listener will be called +// to make event fire immediately upon change, disable the `queueEvents` option on the constructor +await new Promise(resolve => setTimeout(resolve, 0)); +// will print: +// new value: 7 +// previous value: 6 + +eventHandle.dispose(); +``` + +### `State.createCombinedChangeListener` +Create a listener that listens to multiple states and calls the callback when any of the states change. + +```typescript +import {State} from "lifecycle-utils"; + +const valueState1 = new State(6); +const valueState2 = new State("hello"); +const valueState3 = new State(true); + +const eventHandle = State.createCombinedChangeListener([valueState1, valueState2, valueState3], (newValues, previousValues) => { + console.log("new values:", newValues); + console.log("previous values:", previousValues); +}); + +valueState1.state = 7; +valueState2.state = "world"; +valueState3.state = false; + +// after a microtask, the listener will be called +// to make event fire immediately upon change, disable the `queueEvents` option on the constructor +await new Promise(resolve => setTimeout(resolve, 0)); +// will print: +// new values: [7, "world", false] +// previous values: [6, "hello", true] + +eventHandle.dispose(); +``` + +### `splitText` +Split a text by multiple separators, and return a result of the text and separators. + +```typescript +const parts = splitText("Hello world [then] !", ["", "[then]"]); +console.log(parts); // ["Hello ", new Separator(""), " world ", new Separator("[then]"), " !"] +``` + ## Contributing To contribute to `lifecycle-utils` see [CONTRIBUTING.md](https://github.com/giladgd/lifecycle-utils/blob/master/CONTRIBUTING.md).