RxJS Typescript Workshop

Reactive programming, Event Sourcing & CQRS in the frontend

David Sherman

Frontend Dev @ Essent

 

Henk Bakker

Frontend Dev @ Essent

​Making the browser do stuff it wasn't made for

Reactive programming is programming with asynchronous data streams.

"What is Reactive Programming?"

Reactive programming isn't new!

Excel anyone?

Storing all the changes (events) to the system, rather than just its current state.

"What is Event Sourcing?"

Event sourcing

An architecture style that separates read operations from write operations

"What is CQRS?"

* Command Query Responsibility Segregation

CQRS

Back to the browser

Traditionally we are using Promises for async

Promises

Types of async in modern web apps

  • DOM events
  • Animations
  • AJAX
  • WebSockets
  • ServerSendEvents

Promises only really make sense for one of these

  • DOM events

    • 0-N values

  • Animations

    • cancelable

  • AJAX

    • 1 value

  • WebSockets

    • 0-N values

  • ServerSendEvents

    • 0-N values

... except when they don't

  • Single page applications commonly prepare data via AJAX for each view shown
  • When the view changes, the next view probably doesn't care about the previous view's data
  • Fortunately, XHRs can be aborted!
  • .. but promise-based AJAX implementations cannot be aborted, because promises cannot be cancelled

So how do we go from Promises to Observables?

Observable

  • "Streams" or sets
  • Of any number of things
  • Over any amount of time
  • Lazy
    • Observables will not generate values via an underlying producer until they're subscribed to.​
  • Can be "unsubscribed" from.
    • This means the underlying producer can be told to stop and even tear down

Observable

+

Iterator pattern

=

Observer pattern

Both Promises and Observables are built to solve problems around async

(to avoid "callback hell")

fs.readdir(source, function (err, files) {
  if (err) {
    console.log('Error finding files: ' + err)
  } else {
    files.forEach(function (filename, fileIndex) {
      console.log(filename)
      gm(source + filename).size(function (err, values) {
        if (err) {
          console.log('Error identifying file size: ' + err)
        } else {
          console.log(filename + ' : ' + values)
          aspect = (values.width / values.height)
          widths.forEach(function (width, widthIndex) {
            height = Math.round(width / aspect)
            console.log('resizing ' + filename + 'to ' + height + 'x' + height)
            this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
              if (err) console.log('Error writing file: ' + err)
            })
          }.bind(this))
        }
      })
    })
  }
})

Operators

Observables

Schedulers

+

+

=

RxJS

What are these "operators?"

Operators are functions that you can use on Observables that allow you to change the original observable in some manner and return a new observable

JS Array

RxJS Operator

const r = [1, 2, 3, 4, 5, 6]
  .map(x => x * x)
  .filter(y => y % 2 == 0);

console.log(r);

// log: [4, 16, 36]
from([1, 2, 3, 4, 5, 6]).pipe(
  map(x => x * x)
  filter(y => y % 2 == 0)
).subscribe(r => console.log(r));

// log: 4
// log: 16
// log: 36

"RxJS is Lodash for async"

What are we building

Before we dive into code

Workshop Time

Let's code

Hot Observables

Ben Lesh about Hot vs Cold observables

  • Observables are "cold" by default

  • "Cold" observables create a new producer each time a consumer subscribes to them

  • "Hot" observables share a single producer with every consumer that subscribes to them

Learn more about RxJS

Made with Slides.com