Skip to content

Instantly share code, notes, and snippets.

@RobertAKARobin
Last active August 30, 2021 15:46
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RobertAKARobin/47c4777de4d208587b11c63da320b2c0 to your computer and use it in GitHub Desktop.
Save RobertAKARobin/47c4777de4d208587b11c63da320b2c0 to your computer and use it in GitHub Desktop.
Other articles on observables are dumb

Other articles on observables are dumb

1. They use bad examples

Anything can be an observable!! Even data that never changes!!!

const myObservable = Observable.from('Hello world');
myObservable.subscribe(data => console.log(data));

It prints 'Hello world'! Amazing!!

This is dumb. Why would you want to "observe" text that doesn't change? It's like waiting for a flowerpot to talk.

2. They use the word 'stream' like it means somethng

Observables are a stream! They let you stream your streaming data as a stream of streams, streamically!!

So what? What the heck is a stream? Like, Netflix? "Streaming" TV shows? Is this somehow related?

My take

What problem do Observables solve?

Websites and apps deal with a lot of events. An event is when something changes, like:

  • When a user clicks the mouse, the mouse changes from "not clicked" to "clicked."
  • When a website requests data from another website, the computer changes from "not waiting on data from another website" to "waiting on data from another website."
  • When the data finishes loading, the computer changes from "waiting on data from another website" to "not waiting on data from another website" and "having some new data."

JavaScript handles all these events in different ways, and it's really hard to knit them all together.

RxJS takes all the different kinds of events and wraps them up in observables. The idea is no matter what events you're dealing with, you probably want to deal with them the same way:

  1. Wait for stuff to happen
  2. Get new data that wasn't available before it happened
  3. Do something with that new data.

What's an observable?

An observable is something you can watch, waiting for events. A subscription is an instance of watching an observable.

It looks like this:

const Observable = rxjs

const observableForMouseClickEvents = Observable.fromEvent(document, 'click')

function handleMouseClickEvent(clickEvent) {
  console.log('The mouse was clicked!')
}

observableForMouseClickEvents.subscribe(handleMouseClickEvent);

(You could also write import * as Observable from 'rxjs'. I'm doing it this way so that you can copy the above snippet, go to the RxJS website, paste it into the console, and it'll work.)

This is an observable that streams mouse click events.

When you stream a TV show on Netflix, it means Netflix is sending the show in pieces over time, like water in a stream. The alternative would be downloading the entire show before watching it, like water in a puddle.

An observable "streams" data the same way. You subscribe to the observable's stream, and each time new data comes down the stream, that's an event.

Here's a better example

Imagine you've started building a little video game. The player controls a character with a gun. They make the character face left or right using the keyboard's arrow keys. They shoot by clicking the mouse.

Here's how that might look in regular JavaScript, without observables:

let directionToFireWeapon = 'right';

function updateDirectionToFireWeapon(keyboardEvent) {
  if (keyboardEvent.key === 'ArrowRight') {
    directionToFireWeapon = 'right';
  } else if (keyboardEvent.key === 'ArrowLeft') {
    directionToFireWeapon = 'left';
  }
}

function fireWeapon(clickEvent) {
  console.log(`You fired your weapon to the ${directionToFireWeapon}.`);
}

document.addEventListener('keydown', updateDirectionToFireWeapon);

document.addEventListener('click', fireWeapon)

With observables

This example has two event streams that affect each other: firing your weapon depends on mouse events, and how you fire your weapon depends on keyboard events.

RxJS lets us take streams and "pipe" them into little programs combine and change the streams, called operators. You can subscribe to whatever comes "out" of the pipe.

let Observable = rxjs;
let stream = rxjs.operators;

function getDirectionToFireWeapon(keyboardEvent) {
  if (keyboardEvent.key === 'ArrowRight') {
    return 'right';
  } else if (keyboardEvent.key === 'ArrowLeft') {
    return 'left';
  }
}

function fireWeapon([clickEvent, directionToFireWeapon]) {
  console.log(`You fired your weapon to the ${directionToFireWeapon}.`);
}

let streamOfDirectionChangingEvents = Observable.fromEvent(document, 'keydown').pipe(
  stream.map(getDirectionToFireWeapon),
  stream.startWith('right'),
);

let streamOfClickEvents = Observable.fromEvent(document, 'click');

streamOfClickEvents.pipe(
  stream.withLatestFrom(streamOfDirectionChangingEvents),
).subscribe(fireWeapon);

This may look like way more trouble than it's worth

So far, it is. Using observables just requires thinking in a new way, but using operators requires learning their names. There are dozens of operators. Many have weird names. And the documentation is full of confusing explanations. It's like learning a whole new language again.

If you're making a garden-variety website or app, that's probably not worth the effort.

When it's worth the trouble

What if in this game we want to make it so that when the user clicks twice within 500 miliseconds, it counts as only one "fire"?.

That's surprisingly complicated in plain old JavaScript. But RxJS has an operator for it. RxJS has operators for everything. And fortunately, like HTML tags and CSS properties, you use the same small handful of operators for most of the work.

This is called "debouncing" -- treating events that happen in quick succession as one event. It's usually used to keep people from, say, making two purchases when they accidentally click a "buy now" button twice.

With RxJS, we just need to add one line of code:

streamOfClickEvents.pipe(
  stream.debounceTime(500),
  stream.withLatestFrom(streamOfDirectionChangingEvents),
).subscribe(fireWeapon);

What observables give you

RxJS and observables don't give you access to events you couldn't access before. Anything you do with observables, you can do with a combination of Promises, addEventListener, and a half-dozen other JavaScript concepts.

Here's what you get:

1. A standard way of writing code to get data

That standard way is by treating everything as a stream. Standardization is valuable when you're working with a lot of other coders, and it's crucial everyone understand everyone else code.

2. Tools to combine and manipulate lots of different events

This is the reason frameworks like Angular expect you to use observables: they're big, beefy frameworks intended for big, beefy applications that are going to be worked on by big, beefy teams of developers.

Early on in an Angular project, you're going to find yourself banging your head against observables and wondering, "Why?" It's because your app isn't yet to the scale where observables are more of a help than a hinderence. Stay strong: you're laying a solid framework for the future.

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