# Fast-Observables

`fast-observables` is a **1kb** implementation of observables inspired by
[zen-observable](https://github.com/zenparsing/zen-observable) and
[RxJS](https://github.com/ReactiveX/rxjs/). It started out as a simple
experiment on how to write the smallest Observable library and make it as
performant as possible.

## Current state

| Test Name | [RxJS](https://github.com/ReactiveX/rxjs/) | [zen-observable](https://github.com/zenparsing/zen-observable) | **fast-observables** |
| --------- | ------------------------------------------ | -------------------------------------------------------------- | -------------------- |
| map       | 603,187.444                                | 589,813.465                                                    | **634,546.355**      |
| filter    | 445,687.677                                | 450,715.611                                                    | **521,233.32**       |
| scan      | 358,440.041                                | 477,616.099                                                    | **520,379.83**       |
| take      | 382,615.755                                | 463,212.925                                                    | **520,323.069**      |
| flatMap   | 405,864.99                                 | 227,595.825                                                    | **449,218.794**      |

_Note: Measured in operations per second (ops/s). Moreover I didn't measure
async operators because they are really difficult to compare to each other due
to the reliance on timers._

## Installation

```bash
# npm
npm install --save @marvinh/fast-observables

# yarn
yarn add @marvinh/fast-observables
```

## Usage

If reactive-programming is completely new to you, the official
[RxJS-docs](http://reactivex.io/rxjs/manual/index.html) have a great
introduction. These links might also be helpful to crasp the basic concept of
Observables:

* [learn RxJS](https://www.learnrxjs.io/)
* [Introduction to Reactive Programming you've been missing](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754)
* [ReactiveX Overview](http://reactivex.io/documentation/operators.html)

Let's continue! The api of `fast-observables` is pretty similar to
[RxJs](https://github.com/ReactiveX/rxjs/) and
[zen-observable](https://github.com/zenparsing/zen-observable). If you've used
any of these you can easily jump right in.

```js
import { Observable } from "fast-observables";

// For any objects
Observable.of(1, 2, 3).subscribe(x => console.log(x));
// => 1, 2, 3

// For any object that implements `Symbol.iterator` like arrays for example
Observable.from([1, 2, 3]).subscribe(x => console.log(x));
// => 1, 2, 3
```

Note that `fast-observables` follows the composition pragma (or as the RxJs
folks like to call it: lettable operators). In a nutshell this means that
observables can be transformed by applying various transformation functions with
the `pipe` method.

```js
import { Observable, map } from "@marvinh/fast-observables";

Observable.of(1, 2, 3)
  .pipe(map(x => x + x), map(x => x + 1))
  .subscribe(x => console.log(x));
// => 3, 5, 7
```

### Operators

A few handy operators come built-in. If you feel like something is missing,
please open an issue. In case you need a custom one, have a look at the source
on how to write your own. Due to functional composition it is really
straightforward to implement custom operators.

| Name                                               | Description                                                          |
| -------------------------------------------------- | -------------------------------------------------------------------- |
| `changed()`<br/>`changed((prev,x) => prev !== x))` | Only emit next value if the value is different from the previous one |
| `debounce(n)`                                      | Only emit the last value and delay it by `n` ms                      |
| `delay(n)`                                         | Delay emitting of each value by `n` ms                               |
| `debounce(n)`                                      | Only fire when no value is emitted and `n` ms have passed            |
| `delay(n)`                                         | Delay emitting of each value by `n` ms                               |
| `distinct()`                                       | Only emit next value if the value has never been seen before         |
| `filter(x => x > 0)`                               | Only forward elements when `fn` is truthy                            |
| `flatMap(x => Observable.of(x + 1, x +2))`         | Combine all values in the order they arrive                          |
| `map(...fns)`<br/>`map(x => x + 1)`                | Apply a function to transform a value                                |
| `scan((acc, x) => acc + x)`                        | Same as `Array.reduce` but for `Observables`                         |
| `switchMap(x => )`                                 | Combine all values, but only from the most recent Observable         |
| `take(n)`                                          | Take `n` elements and complete the chain                             |
| `throttle(n)`                                      | Drop values until `n` ms have passed                                 |

## FAQ

### Q: Why a new library, why not contribute to RxJS?

This library started is more of a learning experience. For me I find it easiest
to learn new concepts by implementing them myself.

If this experiment is successful and the improvements are good enough, I'll be
happy to contribute to rxjs. Right now the improvements made here are minor and
will likely not affect most real-world apps.

### Q: What makes `fast-observables` faster than other libraries?

The main performance benefit of `fast-observables` is a more performant base
`Observable` class. When creating a new `Observable` instance, all libraries
basically follow these steps:

1. instantiate `Observable`
2. instantiate `Subscription`
3. instantiate `SubscriptionObserver` and attach to `Subscription`
4. attach `Subscription` to `Observable`

This library doesn't need step 3, meaning we save one function call with each
Observable.

The other reason is that `fast-observables` is simply smaller than `rxjs`. This
leads to quicker boot up times and slightly faster operators.

## Credits

This library wouldn't be possible without the amazing work of the rx-community
and its contributors. Their code did help me a lot when figuring out the
interaction between observables, subscribers and how to implement asynchronous
scheduling.

## License

`MIT`, see [License file](LICENSE.md).
