$30 off During Our Annual Pro Sale. View Details »

Everything’s a stream. An introduction to RxJS and avoiding anti-patterns

Everything’s a stream. An introduction to RxJS and avoiding anti-patterns

To reactive extensions, everything's a stream. RxJS simplifies concurrent and async programming in JavaScript by producing and transforming immutable streams, allowing you to easily reason about the events. This talk will give an introduction to using RxJS including common anti-patterns and how to avoid them.

Paul Heasley

June 22, 2017
Tweet

More Decks by Paul Heasley

Other Decks in Programming

Transcript

  1. View Slide

  2. JavaScript

    View Slide

  3. ReactiveUI - An advanced, composable, reactive model-view-viewmodel framework

    View Slide

  4. getDataFromNetwork()
    .filter(s => s != null)
    .map(s => s + 'transformed')
    .forEach(s => console.log(`next => ${s}`))
    getDataFromNetwork()
    .filter(s => s != null)
    .map(s => s + 'transformed')
    .subscribe(s => console.log(`next => ${s}`))

    View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. Rx.Observable.fromEvent(button, 'click')
    .throttleTime(1000)
    .map(event => event.clientX)
    .scan((count, clientX) => count + clientX, 0)
    .subscribe(count => console.log(count));

    View Slide

  9. View Slide

  10. Rx.Observable.fromEvent(document, 'mousemove')
    .subscribe(e =>
    console.log(e.clientX + ', ' + e.clientY));
    // "553, 239"
    // "550, 274"
    // "549, 281"

    View Slide

  11. Rx.Observable.from(['a', 'b', 'c'])
    .subscribe(x => console.log(x));
    // "a"
    // "b"
    // "c"

    View Slide

  12. View Slide

  13. Rx.Observable.from(['a', 'b', 'c'])
    .subscribe(
    x => console.log("next -> " + x),
    x => console.log("error -> " + x),
    () => console.log("complete"));
    // "next -> a"
    // "next -> b"
    // "next -> c"
    // "complete"

    View Slide

  14. View Slide

  15. var foo = Rx.Observable.create(function (observer) {
    observer.next(Math.floor(Math.random() * 100));
    observer.complete();
    });
    foo.subscribe(x => console.log('x: ' + x));
    foo.subscribe(y => console.log('y: ' + y));
    // "x: 84"
    // "y: 96"

    View Slide

  16. View Slide

  17. Rx.Observable.from(['a', 'b', 'c'])
    .scan((acc, curr) => acc + curr, '')
    .subscribe(x => console.log(x));
    // "a"
    // "ab"
    // "abc"

    View Slide

  18. var ints = Rx.Observable.range(0, 3);
    Rx.Observable.from(['a', 'b', 'c'])
    .zip(ints, (a, b) => a + ':' + b)
    .subscribe(x => console.log(x));
    // "a:0"
    // "b:1"
    // "c:2"

    View Slide

  19. getRemoteFolders()
    .mergeMap(folder =>
    getRemoteFiles(folder)
    .map(file => [folder, file]))
    .subscribe(x => console.log(x[0] + '/' + x[1]));
    // "Documents/Receipt.pdf"
    // "Downloads/RxJS.zip"
    // "Pictures/Mum.jpg"
    // "Pictures/Screenshot.png"

    View Slide

  20. Rx.Observable.fromEvent(input, 'input')
    .debounceTime(1000)
    .map(e => e.target.value)
    .subscribe(x => console.log(x));
    // "Goo"
    // "Googling"

    View Slide

  21. and more...

    View Slide

  22. ReactiveX - Operators

    View Slide

  23. View Slide

  24. // Don't
    Rx.Observable.range(1, 2)
    .subscribe(x => {
    Rx.Observable.range(0, x)
    .subscribe(y => console.log(x + ':' + y));
    });
    // Do
    Rx.Observable.range(1, 2)
    .mergeMap(x =>
    Rx.Observable.range(0, x)
    .map(y => [x, y]))
    .subscribe(x => console.log(x[0] + ':' + x[1]));

    View Slide

  25. // Don't
    Rx.Observable.range(1, 2)
    .mergeMap(x =>
    Rx.Observable.range(0, x)
    .do(y => doSomething(x, y)))
    .subscribe({
    complete: () => console.log('done')
    });
    // Do
    Rx.Observable.range(1, 2)
    .mergeMap(x =>
    Rx.Observable.range(0, x)
    .map(y => [x, y]))
    .subscribe({
    next: x => doSomething(x[0], x[1]),
    complete: () => console.log('done')
    });

    View Slide

  26. Rx.Observable.prototype.isLast = function() {
    var source = this;
    var prev = [];
    return Rx.Observable.create(function subscribe(observer) {
    source.subscribe({
    next: v => {
    if (prev.length > 0)
    observer.next({ x: prev[0], isLast: false });
    prev[0] = v
    },
    error: err => observer.error(err),
    complete: () => {
    if (prev.length > 0)
    observer.next({ x: prev[0], isLast: true });
    observer.complete()
    }
    });
    });
    }

    View Slide

  27. View Slide

  28. View Slide

  29. Rx.Observable.fromEvent($('div'), 'click')
    .subscribe(e =>
    console.log(e.clientX + ', ' + e.clientY));

    View Slide

  30. Rx.Observable.interval(1000) // 1 sec
    .subscribe(x => console.log(x));

    View Slide

  31. Rx.Observable.fromEvent(document, 'mousemove')
    .map(e => e.clientX)
    .filter(x => x % 2 == 0)
    .subscribe(x => console.log(x));
    // 378
    // 362
    // 298

    View Slide

  32. Rx.Observable.from(['a', 'b', 'c'])
    .scan((acc, curr) => acc + curr, '')
    .subscribe(x => console.log(x));
    // "a"
    // "ab"
    // "abc"
    Rx.Observable.from(['a', 'b', 'c'])
    .reduce((acc, curr) => acc + curr, '')
    .subscribe(x => console.log(x));
    // "abc"

    View Slide