Skip to content

Instantly share code, notes, and snippets.

@BioPhoton
Last active March 11, 2022 12:39
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save BioPhoton/e8e650dc3b8a7798d09d3a66916bbe10 to your computer and use it in GitHub Desktop.
Save BioPhoton/e8e650dc3b8a7798d09d3a66916bbe10 to your computer and use it in GitHub Desktop.
List of used terms related to reactivity in context of Angular and their description

Reactive Angular Terminology

To have a common terminology I list some of the used terms here and explain their meaning and usage.

Used terms:

  • Asynchronous/Observable Primitive
  • Reactive Primitives
  • Primitive Reactive Problems
  • Bind
  • Connect
  • Side-effect
  • Hold
  • Coalescing of Work
  • @TODO Render Scope
  • @TODO Suspense
  • @TODO Stateful stream
  • @TODO State Derivation
  • @TODO Signaling stream

Asynchronous/Observable Primitive

Asynchronous primitives are either ECMAScript asynchronous types as e.g. Promises, setInterval, etc. Or RxJS creation functions or operators that are observable but pushed values can also be synchronous.

Reactive Primitives

Reactive primitives are pieces of logic in Angular that easily enables reactive programming. The term primitives are important here. Developers or library authors need to have the problems that those primitives solve in an isolated manner. Also, different parts of the needed mechanisms as state composition, rendering, and behavior have their dedicated place to sit. E.g. triggering change detection and therefore rendering should happen in the template. This gives a good idea of what will trigger rendering and may need to get some rate-limiting. State composition should happen in the service layer and derivation in the component.

This helps developers in using exactly what they need and have the features still composable. On top of it, we can

Primitive Reactive Problems

In reactive programming, there are some things that you need to do nearly always in your code. Those things have their scope and by design, RxJS has separate building blocks and separated responsibilities. In the context of reactive Angular, those things also exist in a certain way. This is meant by primitive reactive problems, separated processes not interfering with each other solving specific reactive problems.

Problems:

  • Retrieve asynchronous primitives
  • Subscription handling
  • Connecting observables and values
  • State composition
  • State derivation
  • Change detection and rendering
  • Hold/Maintain side-effects Problems included in the primitives but up to the developer:
  • Processing of observables

It's important to ensure that 'Reactive Primitives' only solve 'Primitive Reactive Problems' to have them flexible and composable as well as ensure the 'Reactive Primitives' can get reused to build other more complex things.

Bind

When "bind" is used in this document is means that some values are bound to a specific variable, class property or input binding or template context. This is very similar to the meaning of the bind() method of a function fn.bind(anyScope). This "binds" the passed value as it's context (this).

Examples for where the word bind is used are listed in the following:

Bind a stream of values to a template binding:

<component [inputBinding]="singleValue"></component>
<component [inputBinding]="observable$ | async"></component>
<component [inputBinding]="observable$ | ngrxPush"></component>

Bind a stream of values to a template context:

<!-- No CD involved -->
{{singleValue}}
<!-- CD involved -->
{{observable$ | async}}
<!-- CD involved -->
{{observable$ | ngrxPush}}
<!-- CD involved -->
<ng-container *ngIf="observable$ | async as observedValue">
{{observedValue}}
</ng-container>
<!-- CD involved -->
<component *ngIf="observable$ | ngrxPush as observedValue">
{{observedValue}}
</component>
<!-- CD involved -->
<ng-container *ngrxLet="observable$ as observedValue">
{{observedValue}}
</ng-container>

Bind a stream of values to a class property:

class AnyClass {
    // CD involved
    prop1 = mikeRyansConnect(observable$);
    
    constructor() {
        michaelsHladkysHold(
            observable$,
            (observedValue) => {
                // Binding happens here. 
                // No CD involved
                this.prop2 = observedValue
            }
        )
    }
}

Connect

When "connect" is used in this document is means that some Observable it connected to another observable in a subscription less manner. Technically this is done over any of the All operators.

The essential thing here is that connect sustains reactivity. No, subscribe happened and the observed values can still be composed. (e.g. derivations of the managed state object or created action observable)

Examples for where the word connect is used are listed in the following:

class AnyClass {

    constructor() {
        michaelsHladkysConnectState(
            observable$.pipe(map(value => ({key: value})))
        );
        michaelsHladkysConnectState(
            'key', observable$
        );
        potentialFutureNgRxStoreConnectAction(
            observable$.pipe(map(value => createAction({prop: value})))
        );
        potentialFutureNgRxStoreConnectAction(
            observable$, value => fetchAction({prop: value})
        );   
    }
}

Side-effect

When "side-effect" is used in this document is means that some logic that is NOT related to any rendered state needs to get run as a side-effect.

The essential thing here is the computed values or applied behavior is NOT related to any rendered state directly. Side-effects ALWAYS have a start and end, and are always owned by some context/component and are tied to the owner's lifetime. (e.g. an interval that interacts with other parts of the application)

Examples for where the word side-effect is used are listed in the following:

function doStuff(value): void {
    some.logic.execute(value)
}

Hold

When "hold" is used in this document is means that some context (class, function scope, etc.) "holds" a side-effect and starts it by subscribing to it.

The essential thing here is that hold helps to make clear who the owner of the side effect is. And also unsubscribes from the side-effect if the owner gets destroyed. (e.g. continues processing of some background task like firing some action)

Examples for where the word hold is used are listed in the following:

class AnyClass {

    constructor() {
        michaelsHladkysHold(
            observable$.pipe(
                // side-effect 
                tap(value => this.ngRxStore.dispatch(fetchAction({prop: value})))
            )
        );
        michaelsHladkysHold(
            observable$,
            // side-effect
            value => this.ngRxStore.dispatch(fetchAction({prop: value}))
        );
    }
}

Coalescing of Work

This term arises from messaging systems or event-driven applications. Also, other areas of IT deal with such scenarios or problems.

To give a practical example of the frontend, imagine you have a rendered thing that relies on 2 data sources to render. IF the 2 sources would change synchrounouse, or as micro-task, this would lead to 2 render template calls in the same browser tick. To avoid this you can coalesce the changes into one and only render one time for the 2 changes.

Another real-life example is angulars Event-Coalescing in Ivy mode. Imagine an application just containing a button. A click on this button would schedule 2 render template calls. This occurs through event bubbling and the way how zone.js and manages asynchronicity.

Angular coalesce those 2 events within an animation frame of the browser. It basically delays the execution of the micro-task stack of the browser.

The sync-task stack (and also the micro-task stack) coalesces changes, the micro-task stack picks them up and schedules the related work. Work is in this case the ApplicationRef.tick

See images of diagrams under Images Coalescing of Work

State

Normalized State

I the first normalisatzin form of database normalization.

Stateful Observalbe

A statful Observalbe is an Observable of state that:

  • Reemitts the last value on subscription
  • Filters out undefined
  • Only forwards distinct values
  • Shares the subscription

State Derivation

Is a statesul Observable derived from a state.

Signaling/Trigger Observalbe

Is a Observable

@BioPhoton
Copy link
Author

BioPhoton commented Feb 4, 2020

Images for Coalescing of Workcoalesce-hc

coalesce-hs
Coalescing of Change Detection_v3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment