Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Connect.Tech 2017: Dive into RxJS Observables

Connect.Tech 2017: Dive into RxJS Observables

Jeremy Fairbank

September 22, 2017
Tweet

More Decks by Jeremy Fairbank

Other Decks in Programming

Transcript

  1. Dive into RxJS
    Jeremy Fairbank
    @elpapapollo / jfairbank
    Observables

    View full-size slide

  2. Software is broken.
    We are here to fix it.
    Say [email protected]

    View full-size slide

  3. Async API
    Callback

    View full-size slide

  4. Callback
    fetchUserById(1, function(err, user) {
    if (err) {
    console.error('Could not retrieve user');
    } else {
    console.log(user);
    }
    });

    View full-size slide

  5. });
    });
    });
    });
    });
    });
    Callback
    Callback
    Callback
    Callback
    Callback
    Callback

    View full-size slide

  6. function fetchCustomerNameForOrder(orderId, done, fail) {
    fetchOrder(orderId, function(err, order) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    fetchCustomer(
    order.customerId,
    function(err, customer) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    done(customer.name);
    }
    }
    );
    }
    });
    }

    View full-size slide

  7. function fetchCustomerNameForOrder(orderId, done, fail) {
    fetchOrder(orderId, function(err, order) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    fetchCustomer(
    order.customerId,
    function(err, customer) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    done(customer.name);
    }
    }
    );
    }
    });
    }

    View full-size slide

  8. function fetchCustomerNameForOrder(orderId, done, fail) {
    fetchOrder(orderId, function(err, order) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    fetchCustomer(
    order.customerId,
    function(err, customer) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    done(customer.name);
    }
    }
    );
    }
    });
    }

    View full-size slide

  9. Promise
    function fetchCustomerNameForOrder(orderId) {
    return fetchOrder(orderId)
    .then(order => fetchCustomer(order.customerId))
    .then(customer => customer.name);
    }

    View full-size slide

  10. .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)

    View full-size slide

  11. Error
    Error
    Error
    Error

    View full-size slide

  12. function fetchCustomerNameForOrder(orderId) {
    return fetchOrder(orderId)
    .then(order => fetchCustomer(order.customerId))
    .then(customer => customer.name)
    .catch(err => {
    logError(err);
    throw err;
    });
    }

    View full-size slide

  13. Getting there…

    View full-size slide

  14. • More readable and
    maintainable async code
    • Better error handling
    • More declarative and
    versatile syntax
    • Capable of handling events,
    streams, and HTTP

    View full-size slide

  15. RxJS
    Observables

    View full-size slide

  16. Arrays
    [ 1, 2, 3, 4, 5 ]
    Sequences in space

    View full-size slide

  17. Observables
    Sequences in time
    1 2 3 4 5

    View full-size slide

  18. const { Observable } = require('rxjs');
    const source = Observable.of(1, 2, 3);
    source.subscribe(x => console.log(x));
    // 1
    // 2
    // 3

    View full-size slide

  19. const { Observable } = require('rxjs');
    const source = Observable.of(1, 2, 3);
    source.subscribe(x => console.log(x));
    // 1
    // 2
    // 3

    View full-size slide

  20. const { Observable } = require('rxjs');
    const source = Observable.of(1, 2, 3);
    source.subscribe(x => console.log(x));
    // 1
    // 2
    // 3

    View full-size slide

  21. const { Observable } = require('rxjs');
    const source = Observable.of(1, 2, 3);
    source.subscribe(x => console.log(x));
    // 1
    // 2
    // 3

    View full-size slide

  22. Observable.of(1, 2, 3)
    .subscribe(x => console.log(x));
    console.log
    subscribe

    View full-size slide

  23. Observable.of(1, 2, 3)
    .subscribe(x => console.log(x));
    console.log
    subscribe
    1

    View full-size slide

  24. Observable.of(1, 2, 3)
    .subscribe(x => console.log(x));
    console.log
    subscribe
    1

    View full-size slide

  25. Observable.of(1, 2, 3)
    .subscribe(x => console.log(x));
    console.log
    subscribe

    View full-size slide

  26. Observable.of(1, 2, 3)
    .subscribe(x => console.log(x));
    console.log
    subscribe
    2

    View full-size slide

  27. Observable.of(1, 2, 3)
    .subscribe(x => console.log(x));
    console.log
    subscribe
    2

    View full-size slide

  28. Observable.of(1, 2, 3)
    .subscribe(x => console.log(x));
    console.log
    subscribe

    View full-size slide

  29. Observable.of(1, 2, 3)
    .subscribe(x => console.log(x));
    console.log
    subscribe
    3

    View full-size slide

  30. Observable.of(1, 2, 3)
    .subscribe(x => console.log(x));
    console.log
    subscribe
    3

    View full-size slide

  31. Declarative
    Transformation
    Operate on events

    View full-size slide

  32. Observable.of(1, 2, 3)
    .map(n => n * 2)
    .subscribe(x => console.log(x));
    // 2
    // 4
    // 6

    View full-size slide

  33. Observable.of(1, 2, 3)
    .map(n => n * 2)
    .subscribe(x => console.log(x));
    // 2
    // 4
    // 6

    View full-size slide

  34. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe

    View full-size slide

  35. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    1

    View full-size slide

  36. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    1

    View full-size slide

  37. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    2

    View full-size slide

  38. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    2

    View full-size slide

  39. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe

    View full-size slide

  40. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    2

    View full-size slide

  41. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    2

    View full-size slide

  42. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    4

    View full-size slide

  43. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    4

    View full-size slide

  44. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe

    View full-size slide

  45. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    3

    View full-size slide

  46. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    3

    View full-size slide

  47. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    6

    View full-size slide

  48. Observable.of(1, 2, 3)
    console.log
    n * 2
    map subscribe
    6

    View full-size slide

  49. Lazy Transformation
    Do only as much work as
    needed

    View full-size slide

  50. Observable.range(1, 100)
    .map(n => n * 2)
    .filter(n => n > 4)
    .take(2)
    .subscribe(x => console.log(x));
    // 6
    // 8

    View full-size slide

  51. Observable.range(1, 100)
    .map(n => n * 2)
    .filter(n => n > 4)
    .take(2)
    .subscribe(x => console.log(x));
    // 6
    // 8

    View full-size slide

  52. Observable.range(1, 100)
    .map(n => n * 2)
    .filter(n => n > 4)
    .take(2)
    .subscribe(x => console.log(x));
    // 6
    // 8

    View full-size slide

  53. Observable.range(1, 100)
    .map(n => n * 2)
    .filter(n => n > 4)
    .take(2)
    .subscribe(x => console.log(x));
    // 6
    // 8

    View full-size slide

  54. Observable.range(1, 100)
    .map(n => n * 2)
    .filter(n => n > 4)
    .take(2)
    .subscribe(x => console.log(x));
    // 6
    // 8

    View full-size slide

  55. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  56. console.log
    n * 2
    map subscribe
    n > 4
    1
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  57. console.log
    n * 2
    map subscribe
    n > 4
    1
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  58. console.log
    n * 2
    map subscribe
    n > 4
    2
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  59. console.log
    n * 2
    map subscribe
    n > 4
    2
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  60. console.log
    n * 2
    map subscribe
    n > 4
    2
    Observable.range(1, 100)
    filter
    2
    take
    ×

    View full-size slide

  61. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  62. console.log
    n * 2
    map subscribe
    n > 4
    2
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  63. console.log
    n * 2
    map subscribe
    n > 4
    2
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  64. console.log
    n * 2
    map subscribe
    n > 4
    4
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  65. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    2
    take
    4

    View full-size slide

  66. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    2
    take
    4
    ×

    View full-size slide

  67. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  68. console.log
    n * 2
    map subscribe
    n > 4
    3
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  69. console.log
    n * 2
    map subscribe
    n > 4
    3
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  70. console.log
    n * 2
    map subscribe
    n > 4
    6
    Observable.range(1, 100)
    filter
    2
    take

    View full-size slide

  71. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    2
    take
    6

    View full-size slide


  72. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    2
    take
    6

    View full-size slide

  73. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    2
    take
    6

    View full-size slide

  74. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    1
    take
    6

    View full-size slide

  75. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    1
    take

    View full-size slide

  76. console.log
    n * 2
    map subscribe
    n > 4
    4
    Observable.range(1, 100)
    filter
    1
    take

    View full-size slide

  77. console.log
    n * 2
    map subscribe
    n > 4
    4
    Observable.range(1, 100)
    filter
    1
    take

    View full-size slide

  78. console.log
    n * 2
    map subscribe
    n > 4
    8
    Observable.range(1, 100)
    filter
    1
    take

    View full-size slide

  79. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    1
    take
    8

    View full-size slide


  80. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    1
    take
    8

    View full-size slide

  81. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    1
    take
    8

    View full-size slide

  82. console.log
    n * 2
    map subscribe
    n > 4
    Observable.range(1, 100)
    filter
    0
    take
    8

    View full-size slide

  83. let counter = 0;
    function updateCounter(n) {
    counter += n;
    counterEl.innerHTML = counter;
    }
    incrementBtn.addEventListener('click', () => {
    updateCounter(1);
    });
    decrementBtn.addEventListener('click', () => {
    updateCounter(-1);
    });

    View full-size slide

  84. let counter = 0;
    function updateCounter(n) {
    counter += n;
    counterEl.innerHTML = counter;
    }
    incrementBtn.addEventListener('click', () => {
    updateCounter(1);
    });
    decrementBtn.addEventListener('click', () => {
    updateCounter(-1);
    });

    View full-size slide

  85. Observable.fromEvent(incrementBtn, 'click')
    .mapTo(1)
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  86. Observable.fromEvent(incrementBtn, 'click')
    .mapTo(1)
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  87. Observable.fromEvent(incrementBtn, 'click')
    .mapTo(1)
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  88. Observable.fromEvent(incrementBtn, 'click')
    .mapTo(1)
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  89. Observable.fromEvent(incrementBtn, 'click')
    .mapTo(1)
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  90. Observable.fromEvent(incrementBtn, 'click')
    .mapTo(1)
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  91. Observable.fromEvent(incrementBtn, 'click')
    .mapTo(1)
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  92. .scan((acc, curr) => acc + curr, 0)
    Accumulated
    counter value

    View full-size slide

  93. .scan((acc, curr) => acc + curr, 0)
    Current event
    value (1)

    View full-size slide

  94. .scan((acc, curr) => acc + curr, 0)
    Return new accumulated
    counter value

    View full-size slide

  95. .scan((acc, curr) => acc + curr, 0)
    Initial counter
    value

    View full-size slide

  96. counterEl.innerHTML =
    counter
    acc + curr
    1
    mapTo subscribe
    0
    scan

    View full-size slide

  97. acc + curr
    1
    mapTo subscribe
    e
    scan
    0
    counterEl.innerHTML =
    counter

    View full-size slide

  98. 1
    mapTo subscribe
    e
    scan
    acc + curr
    0
    counterEl.innerHTML =
    counter

    View full-size slide

  99. 1
    mapTo subscribe
    1
    scan
    acc + curr
    0
    counterEl.innerHTML =
    counter

    View full-size slide

  100. 1
    mapTo subscribe
    scan
    1
    acc + curr
    0
    counterEl.innerHTML =
    counter

    View full-size slide

  101. 1
    mapTo subscribe
    scan
    1
    acc + curr
    1
    Counter value
    counterEl.innerHTML =
    counter

    View full-size slide

  102. 1
    mapTo subscribe
    scan
    1
    acc + curr
    1
    counterEl.innerHTML =
    counter

    View full-size slide

  103. acc + curr
    1
    mapTo subscribe
    scan
    1
    counterEl.innerHTML =
    counter

    View full-size slide

  104. acc + curr
    1
    mapTo subscribe
    e
    scan
    1
    counterEl.innerHTML =
    counter

    View full-size slide

  105. 1
    mapTo subscribe
    e
    scan
    acc + curr
    1
    counterEl.innerHTML =
    counter

    View full-size slide

  106. 1
    mapTo subscribe
    1
    scan
    acc + curr
    1
    counterEl.innerHTML =
    counter

    View full-size slide

  107. 1
    mapTo subscribe
    scan
    1
    acc + curr
    1
    counterEl.innerHTML =
    counter

    View full-size slide

  108. 1
    mapTo subscribe
    scan
    2
    acc + curr
    2
    Counter value
    counterEl.innerHTML =
    counter

    View full-size slide

  109. 1
    mapTo subscribe
    scan
    2
    acc + curr
    2
    counterEl.innerHTML =
    counter

    View full-size slide

  110. const source = Observable.merge(
    Observable.fromEvent(incrementBtn, 'click').mapTo(1),
    Observable.fromEvent(decrementBtn, 'click').mapTo(-1),
    );
    source
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  111. const source = Observable.merge(
    Observable.fromEvent(incrementBtn, 'click').mapTo(1),
    Observable.fromEvent(decrementBtn, 'click').mapTo(-1),
    );
    source
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  112. const source = Observable.merge(
    Observable.fromEvent(incrementBtn, 'click').mapTo(1),
    Observable.fromEvent(decrementBtn, 'click').mapTo(-1),
    );
    source
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  113. const source = Observable.merge(
    Observable.fromEvent(incrementBtn, 'click').mapTo(1),
    Observable.fromEvent(decrementBtn, 'click').mapTo(-1),
    );
    source
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  114. const source = Observable.merge(
    Observable.fromEvent(incrementBtn, 'click').mapTo(1),
    Observable.fromEvent(decrementBtn, 'click').mapTo(-1),
    );
    source
    .scan((acc, curr) => acc + curr, 0)
    .subscribe((counter) => {
    counterEl.innerHTML = counter;
    });

    View full-size slide

  115. acc + curr
    1
    mapTo
    subscribe
    0
    scan
    -1
    mapTo
    Increment
    Decrement
    counterEl.innerHTML =
    counter

    View full-size slide

  116. acc + curr
    1
    mapTo
    subscribe
    0
    scan
    -1
    mapTo
    Increment
    Decrement
    e
    counterEl.innerHTML =
    counter

    View full-size slide

  117. acc + curr
    1
    mapTo
    subscribe
    0
    scan
    -1
    mapTo
    Increment
    Decrement
    e
    counterEl.innerHTML =
    counter

    View full-size slide

  118. acc + curr
    1
    mapTo
    subscribe
    0
    scan
    -1
    mapTo
    Increment
    Decrement
    1
    counterEl.innerHTML =
    counter

    View full-size slide

  119. acc + curr
    1
    mapTo
    subscribe
    0
    scan
    -1
    mapTo
    Increment
    Decrement
    1
    counterEl.innerHTML =
    counter

    View full-size slide

  120. acc + curr
    1
    mapTo
    subscribe
    1
    scan
    -1
    mapTo
    Increment
    Decrement
    1
    counterEl.innerHTML =
    counter

    View full-size slide

  121. acc + curr
    1
    mapTo
    subscribe
    1
    scan
    -1
    mapTo
    Increment
    Decrement
    1
    counterEl.innerHTML =
    counter

    View full-size slide

  122. acc + curr
    1
    mapTo
    subscribe
    1
    scan
    -1
    mapTo
    Increment
    Decrement
    counterEl.innerHTML =
    counter

    View full-size slide

  123. acc + curr
    1
    mapTo
    subscribe
    1
    scan
    -1
    mapTo
    Increment
    Decrement
    e
    counterEl.innerHTML =
    counter

    View full-size slide

  124. acc + curr
    1
    mapTo
    subscribe
    1
    scan
    -1
    mapTo
    Increment
    Decrement
    e
    counterEl.innerHTML =
    counter

    View full-size slide

  125. acc + curr
    1
    mapTo
    subscribe
    1
    scan
    -1
    mapTo
    Increment
    Decrement
    -1
    counterEl.innerHTML =
    counter

    View full-size slide

  126. acc + curr
    1
    mapTo
    subscribe
    1
    scan
    -1
    mapTo
    Increment
    Decrement
    -1
    counterEl.innerHTML =
    counter

    View full-size slide

  127. acc + curr
    1
    mapTo
    subscribe
    0
    scan
    -1
    mapTo
    Increment
    Decrement
    0
    counterEl.innerHTML =
    counter

    View full-size slide

  128. acc + curr
    1
    mapTo
    subscribe
    0
    scan
    -1
    mapTo
    Increment
    Decrement
    0
    counterEl.innerHTML =
    counter

    View full-size slide

  129. Promise
    fetchOrders()
    .then((orders) => {
    orders.forEach((order) => {
    console.log(order);
    });
    });

    View full-size slide

  130. Promise
    fetchOrders()
    .then((orders) => {
    orders.forEach((order) => {
    console.log(order);
    });
    });

    View full-size slide

  131. Observable
    fetchOrders()
    .subscribe((orders) => {
    orders.forEach((order) => {
    console.log(order);
    });
    });

    View full-size slide

  132. Why Observables?

    View full-size slide

  133. Promise
    fetchOrders()
    .then(orders => orders.filter(
    order => order.customerName === 'Tucker'
    ))
    .then(orders => orders.map(order => order.id))
    .then((orderIds) => {
    orderIds.forEach(id => console.log(id));
    });

    View full-size slide

  134. Promise
    fetchOrders()
    .then(orders => orders.filter(
    order => order.customerName === 'Tucker'
    ))
    .then(orders => orders.map(order => order.id))
    .then((orderIds) => {
    orderIds.forEach(id => console.log(id));
    });

    View full-size slide

  135. Promise
    fetchOrders()
    .then(orders => orders.filter(
    order => order.customerName === 'Tucker'
    ))
    .then(orders => orders.map(order => order.id))
    .then((orderIds) => {
    orderIds.forEach(id => console.log(id));
    });

    View full-size slide

  136. Promise
    fetchOrders()
    .then(orders => orders.filter(
    order => order.customerName === 'Tucker'
    ))
    .then(orders => orders.map(order => order.id))
    .then((orderIds) => {
    orderIds.forEach(id => console.log(id));
    });

    View full-size slide

  137. fetchOrders()
    .mergeAll()
    .filter(
    order => order.customerName === 'Tucker'
    )
    .map(order => order.id)
    .subscribe(id => console.log(id));
    Observable

    View full-size slide

  138. fetchOrders()
    .mergeAll()
    .filter(
    order => order.customerName === 'Tucker'
    )
    .map(order => order.id)
    .subscribe(id => console.log(id));
    Observable

    View full-size slide

  139. fetchOrders()
    .mergeAll()
    .filter(
    order => order.customerName === 'Tucker'
    )
    .map(order => order.id)
    .subscribe(id => console.log(id));
    Observable

    View full-size slide

  140. fetchOrders()
    .mergeAll()
    .filter(
    order => order.customerName === 'Tucker'
    )
    .map(order => order.id)
    .subscribe(id => console.log(id));
    Observable

    View full-size slide

  141. fetchOrders()
    .mergeAll()
    .filter(
    order => order.customerName === 'Tucker'
    )
    .map(order => order.id)
    .subscribe(id => console.log(id));
    Observable

    View full-size slide

  142. Cancellation

    View full-size slide

  143. const promise = fetchOrders()
    .then((orders) => {
    orders.forEach((order) => {
    console.log(order);
    });
    });
    promise.cancel();
    Promise

    View full-size slide

  144. const promise = fetchOrders()
    .then((orders) => {
    orders.forEach((order) => {
    console.log(order);
    });
    });
    promise.cancel();
    Promise

    View full-size slide

  145. const promise = fetchOrders()
    .then((orders) => {
    orders.forEach((order) => {
    console.log(order);
    });
    });
    promise.cancel();
    Promise
    ×

    View full-size slide

  146. const subscription = fetchOrders()
    .subscribe((orders) => {
    orders.forEach((order) => {
    console.log(order);
    });
    });
    subscription.unsubscribe();
    Observable

    View full-size slide

  147. const subscription = fetchOrders()
    .subscribe((orders) => {
    orders.forEach((order) => {
    console.log(order);
    });
    });
    subscription.unsubscribe();
    Observable
    Cancel request

    View full-size slide

  148. Lazy
    Subscriptions

    View full-size slide

  149. const p1 = fetchOrders();
    const p2 = fetchOrders();
    const p3 = fetchOrders();
    Promises

    View full-size slide

  150. const p1 = fetchOrders();
    const p2 = fetchOrders();
    const p3 = fetchOrders();
    Promises
    Immediate

    View full-size slide

  151. Observables
    const o1 = fetchOrders();
    const o2 = fetchOrders();
    const o3 = fetchOrders();
    o1.subscribe();
    o2.subscribe();
    o3.subscribe();

    View full-size slide

  152. Observables
    Lazy
    const o1 = fetchOrders();
    const o2 = fetchOrders();
    const o3 = fetchOrders();
    o1.subscribe();
    o2.subscribe();
    o3.subscribe();

    View full-size slide

  153. Observables
    Lazy
    const o1 = fetchOrders();
    const o2 = fetchOrders();
    const o3 = fetchOrders();
    o1.subscribe();
    o2.subscribe();
    o3.subscribe();
    Issue Request

    View full-size slide

  154. const o1 = fetchOrders();
    o1.subscribe();
    o1.subscribe();
    o1.subscribe();

    View full-size slide

  155. const o1 = fetchOrders();
    o1.subscribe();
    o1.subscribe();
    o1.subscribe();
    Pure,
    shareable
    value

    View full-size slide

  156. const o1 = fetchOrders();
    o1.subscribe();
    o1.subscribe();
    o1.subscribe();
    Issue new request
    with same
    observable
    Pure,
    shareable
    value

    View full-size slide

  157. Create HTTP
    Requests

    View full-size slide

  158. function fetchOrders() {
    return Observable.ajax.get('/orders');
    }
    Built-in AJAX

    View full-size slide

  159. function fetchOrders() {
    return Observable.ajax.get('/orders');
    }
    Built-in AJAX

    View full-size slide

  160. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }
    Custom Observable
    Creation

    View full-size slide

  161. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }
    Custom Observable
    Creation

    View full-size slide

  162. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }
    Custom Observable
    Creation

    View full-size slide

  163. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }
    Custom Observable
    Creation

    View full-size slide

  164. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }
    Custom Observable
    Creation

    View full-size slide

  165. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }
    Custom Observable
    Creation

    View full-size slide

  166. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }
    Custom Observable
    Creation
    ?

    View full-size slide

  167. Observable.of(1, 2, 3)
    .subscribe(x => console.log(x));

    View full-size slide

  168. Observable.of(1, 2, 3)
    .subscribe(x => console.log(x));
    Subscriber
    (or Observer)

    View full-size slide

  169. Observable.of(1, 2, 3)
    .subscribe({
    next: x => console.log(x),
    });
    Subscriber Object

    View full-size slide

  170. Observable.of(1, 2, 3)
    .subscribe({
    next: x => console.log(x),
    complete: () => console.log('Done!'),
    });
    // 1
    // 2
    // 3
    // Done!

    View full-size slide

  171. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }
    fetchOrders().mergeAll().subscribe({
    next: x => console.log(x),
    complete: () => console.log('Done!'),
    });

    View full-size slide

  172. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }
    fetchOrders().mergeAll().subscribe({
    next: x => console.log(x),
    complete: () => console.log('Done!'),
    });

    View full-size slide

  173. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }
    fetchOrders().mergeAll().subscribe({
    next: x => console.log(x),
    complete: () => console.log('Done!'),
    });

    View full-size slide

  174. Error Handling

    View full-size slide

  175. const source = Observable.create((subscriber) => {
    subscriber.next(1);
    subscriber.error(new Error('Uh oh'));
    subscriber.next(2);
    });
    source.subscribe({
    next: x => console.log(x),
    complete: () => console.log('Done!'),
    error: e => console.error(e),
    });
    // 1
    // Error: Uh oh

    View full-size slide

  176. const source = Observable.create((subscriber) => {
    subscriber.next(1);
    subscriber.error(new Error('Uh oh'));
    subscriber.next(2);
    });
    source.subscribe({
    next: x => console.log(x),
    complete: () => console.log('Done!'),
    error: e => console.error(e),
    });
    // 1
    // Error: Uh oh

    View full-size slide

  177. const source = Observable.create((subscriber) => {
    subscriber.next(1);
    subscriber.error(new Error('Uh oh'));
    subscriber.next(2);
    });
    source.subscribe({
    next: x => console.log(x),
    complete: () => console.log('Done!'),
    error: e => console.error(e),
    });
    // 1
    // Error: Uh oh

    View full-size slide

  178. const source = Observable.create((subscriber) => {
    subscriber.next(1);
    subscriber.error(new Error('Uh oh'));
    subscriber.next(2);
    });
    source.subscribe({
    next: x => console.log(x),
    complete: () => console.log('Done!'),
    error: e => console.error(e),
    });
    // 1
    // Error: Uh oh
    Never called

    View full-size slide

  179. const source = Observable.create((subscriber) => {
    subscriber.next(1);
    subscriber.error(new Error('Uh oh'));
    subscriber.next(2);
    });
    source.subscribe(x => console.log(x));
    No error handler, so
    what happens?

    View full-size slide

  180. Error
    Error
    Error
    Error
    Promises

    View full-size slide

  181. const source = Observable.create((subscriber) => {
    subscriber.next(1);
    subscriber.error(new Error('Uh oh'));
    subscriber.next(2);
    });
    source.subscribe(x => console.log(x));
    No swallowed errors!

    View full-size slide

  182. fetchOrders()
    .catch((e) => {
    logError(e);
    return legacyFetchOrders()
    .catch((e2) => {
    logError(e2);
    return Observable.of([]);
    })
    })
    .subscribe(x => console.log(x));
    Catching

    View full-size slide

  183. fetchOrders()
    .catch((e) => {
    logError(e);
    return legacyFetchOrders()
    .catch((e2) => {
    logError(e2);
    return Observable.of([]);
    })
    })
    .subscribe(x => console.log(x));
    Catching

    View full-size slide

  184. fetchOrders()
    .catch((e) => {
    logError(e);
    return legacyFetchOrders()
    .catch((e2) => {
    logError(e2);
    return Observable.of([]);
    })
    })
    .subscribe(x => console.log(x));
    Catching

    View full-size slide

  185. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])

    View full-size slide

  186. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])

    View full-size slide

  187. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])

    View full-size slide

  188. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])

    View full-size slide

  189. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])
    ×

    View full-size slide

  190. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])
    ×

    View full-size slide

  191. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])
    ×

    View full-size slide

  192. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])
    ×

    View full-size slide

  193. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])
    × ✓

    View full-size slide

  194. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])

    View full-size slide

  195. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])
    ×

    View full-size slide

  196. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])
    ×

    View full-size slide

  197. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])
    ×

    View full-size slide

  198. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])
    ×
    ×

    View full-size slide

  199. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])
    ×
    ×

    View full-size slide

  200. console.log
    catch subscribe
    legacyFetchOrders()
    fetchOrders()
    catch
    Observable.of([])
    ×
    ×
    []

    View full-size slide

  201. Observable
    creates the source
    Cold

    View full-size slide

  202. Best for one-off
    unique requests.
    Cold

    View full-size slide

  203. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }

    View full-size slide

  204. function fetchOrders() {
    return Observable.create((subscriber) => {
    fetchOrdersFromDb((orders) => {
    subscriber.next(orders);
    subscriber.complete();
    });
    });
    }
    Resource requested/created
    at subscription time

    View full-size slide

  205. function ordersStream() {
    return Observable.create((subscriber) => {
    const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    });
    }

    View full-size slide

  206. function ordersStream() {
    return Observable.create((subscriber) => {
    const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    });
    }

    View full-size slide

  207. function ordersStream() {
    return Observable.create((subscriber) => {
    const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    });
    }

    View full-size slide

  208. function ordersStream() {
    return Observable.create((subscriber) => {
    const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    });
    }

    View full-size slide

  209. const stream = ordersStream();
    stream.subscribe(x => console.log(x));

    View full-size slide

  210. subscriber
    .next(data)
    WebSocket
    Subscribed
    Observable
    console.log
    stream.subscribe(x => console.log(x));

    View full-size slide

  211. subscriber
    .next(data)
    ...
    WebSocket
    Subscribed
    Observable
    console.log
    stream.subscribe(x => console.log(x));

    View full-size slide

  212. subscriber
    .next(data)
    ...
    WebSocket
    Subscribed
    Observable
    console.log
    stream.subscribe(x => console.log(x));

    View full-size slide

  213. subscriber
    .next(data)
    ...
    WebSocket
    Subscribed
    Observable
    console.log
    stream.subscribe(x => console.log(x));

    View full-size slide

  214. subscriber
    .next(data)
    ...
    WebSocket
    Subscribed
    Observable
    console.log
    stream.subscribe(x => console.log(x));

    View full-size slide

  215. .subscribe(...)

    View full-size slide

  216. .subscribe(...) .subscribe(...)

    View full-size slide

  217. .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View full-size slide

  218. .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View full-size slide

  219. .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View full-size slide

  220. .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View full-size slide

  221. .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View full-size slide

  222. .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View full-size slide

  223. Hot
    Observable
    closes over the source

    View full-size slide

  224. Hot
    Best for multicasting
    and sharing resources.

    View full-size slide

  225. const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    function ordersStream() {
    return Observable.create((subscriber) => {
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    });
    }

    View full-size slide

  226. const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    function ordersStream() {
    return Observable.create((subscriber) => {
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    });
    }
    Resource created
    outside subscription

    View full-size slide

  227. const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    function ordersStream() {
    return Observable.create((subscriber) => {
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    });
    } Close over existing
    resource when subscribing

    View full-size slide

  228. const stream = ordersStream();
    const sub1 = stream.subscribe(x => console.log(x));
    const sub2 = stream.subscribe(x => console.log(x));

    View full-size slide

  229. Shared stream of data
    const stream = ordersStream();
    const sub1 = stream.subscribe(x => console.log(x));
    const sub2 = stream.subscribe(x => console.log(x));

    View full-size slide

  230. subscriber
    .next(event.data)
    WebSocket
    Subscribed
    Observable
    console.log
    stream.subscribe(x => console.log(x))

    View full-size slide

  231. subscriber
    .next(event.data)
    ...
    WebSocket
    Subscribed
    Observable
    console.log
    stream.subscribe(x => console.log(x))

    View full-size slide

  232. subscriber
    .next(event.data)
    ...
    WebSocket
    Subscribed
    Observable
    console.log
    stream.subscribe(x => console.log(x))

    View full-size slide

  233. subscriber
    .next(event.data)
    ...
    WebSocket
    Subscribed
    Observable
    console.log
    stream.subscribe(x => console.log(x))

    View full-size slide

  234. subscriber
    .next(event.data)
    ...
    WebSocket
    Subscribed
    Observable
    console.log
    stream.subscribe(x => console.log(x))

    View full-size slide

  235. subscriber
    .next(event.data)
    WebSocket
    Subscribed
    Observable
    console.log
    New Subscribed
    Observable
    console.log
    stream.subscribe(...)
    stream.subscribe(...)

    View full-size slide

  236. subscriber
    .next(event.data)
    WebSocket
    Subscribed
    Observable
    console.log
    ...
    New Subscribed
    Observable
    console.log
    stream.subscribe(...)
    stream.subscribe(...)

    View full-size slide

  237. subscriber
    .next(event.data)
    WebSocket
    Subscribed
    Observable
    console.log
    ...
    New Subscribed
    Observable
    console.log
    stream.subscribe(...)
    stream.subscribe(...)

    View full-size slide

  238. subscriber
    .next(event.data)
    WebSocket
    Subscribed
    Observable
    console.log
    ...
    New Subscribed
    Observable
    console.log
    ...
    stream.subscribe(...)
    stream.subscribe(...)

    View full-size slide

  239. subscriber
    .next(event.data)
    ...
    WebSocket
    Subscribed
    Observable
    console.log
    ...
    New Subscribed
    Observable
    console.log
    stream.subscribe(...)
    stream.subscribe(...)

    View full-size slide

  240. function ordersStream() {
    return Observable.create((subscriber) => {
    const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    })
    .share();
    }
    Share It

    View full-size slide

  241. function ordersStream() {
    return Observable.create((subscriber) => {
    const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    })
    .share();
    }
    Share It

    View full-size slide

  242. function ordersStream() {
    return Observable.create((subscriber) => {
    const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    })
    .share();
    }
    Share It

    View full-size slide

  243. const stream = ordersStream();
    const sub1 = stream.subscribe(x => console.log(x));
    const sub2 = stream.subscribe(x => console.log(x));

    View full-size slide

  244. Shared stream of data too
    const stream = ordersStream();
    const sub1 = stream.subscribe(x => console.log(x));
    const sub2 = stream.subscribe(x => console.log(x));

    View full-size slide

  245. function ordersStream() {
    return Observable.create((subscriber) => {
    const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    return () => {
    socket.close();
    };
    })
    .share();
    }

    View full-size slide

  246. function ordersStream() {
    return Observable.create((subscriber) => {
    const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    return () => {
    socket.close();
    };
    })
    .share();
    }
    Called when all subscriptions
    unsubscribe

    View full-size slide

  247. function ordersStream() {
    return Observable.create((subscriber) => {
    const url = 'ws://example.com/orders';
    const socket = new WebSocket(url);
    socket.addEventListener('message', (data) => {
    subscriber.next(data);
    });
    return () => {
    socket.close();
    };
    })
    .share();
    }
    Close socket,
    deallocate resources,
    etc.

    View full-size slide

  248. fetchOrders()
    .mergeAll()
    .filter(
    order => order.customerName === 'Tucker'
    )
    .map(order => order.id)
    .subscribe(id => console.log(id));
    Recall

    View full-size slide

  249. fetchOrders()
    .mergeAll()
    .filter(
    order => order.customerName === 'Tucker'
    )
    .map(order => order.id)
    .subscribe(id => console.log(id));
    ?
    Recall

    View full-size slide

  250. Observable.of([1, 2, 3])
    .subscribe(x => console.log(x));
    // [ 1, 2, 3 ]

    View full-size slide

  251. Observable.of([1, 2, 3])
    .subscribe(x => console.log(x));
    // [ 1, 2, 3 ]

    View full-size slide

  252. Observable.of([1, 2, 3])
    .subscribe(x => console.log(x));
    // [ 1, 2, 3 ]

    View full-size slide

  253. Observable.of([1, 2, 3])
    .mergeAll()
    .subscribe(x => console.log(x));
    // 1
    // 2
    // 3

    View full-size slide

  254. Observable.of([1, 2, 3])
    .mergeAll()
    .subscribe(x => console.log(x));
    // 1
    // 2
    // 3
    Flatten

    View full-size slide

  255. Observable.of([1, 2, 3])
    .mergeAll()
    .subscribe(x => console.log(x));
    // 1
    // 2
    // 3

    View full-size slide

  256. subscribe
    mergeAll
    console.log
    [1, 2, 3]

    View full-size slide

  257. subscribe
    mergeAll
    console.log
    [1, 2, 3]

    View full-size slide

  258. subscribe
    mergeAll
    console.log
    [2, 3] 1

    View full-size slide

  259. subscribe
    mergeAll
    console.log
    [2, 3] 1

    View full-size slide

  260. subscribe
    mergeAll
    console.log
    [3] 2

    View full-size slide

  261. subscribe
    mergeAll
    console.log
    [3] 2

    View full-size slide

  262. subscribe
    mergeAll
    console.log
    3

    View full-size slide

  263. subscribe
    mergeAll
    console.log
    3

    View full-size slide

  264. Higher Order
    Observables

    View full-size slide

  265. Observable.of(1, 2, 3)
    .map(n => n * 2)
    .subscribe(x => console.log(x));
    // 2
    // 4
    // 6

    View full-size slide

  266. Observable.of(1, 2, 3)
    .map(n => n * 2)
    .subscribe(x => console.log(x));
    // 2
    // 4
    // 6
    Delay?

    View full-size slide

  267. Observable.of(1, 2, 3)
    .map(n => Observable.of(n * 2))
    .subscribe(x => console.log(x));
    // ScalarObservable { value: 2 }
    // ScalarObservable { value: 4 }
    // ScalarObservable { value: 6 }

    View full-size slide

  268. Observable.of(1, 2, 3)
    .map(n => Observable.of(n * 2))
    .subscribe(x => console.log(x));
    // ScalarObservable { value: 2 }
    // ScalarObservable { value: 4 }
    // ScalarObservable { value: 6 }

    View full-size slide

  269. Observable.of(1, 2, 3)
    .map(n => Observable.of(n * 2))
    .subscribe(x => console.log(x));
    // ScalarObservable { value: 2 }
    // ScalarObservable { value: 4 }
    // ScalarObservable { value: 6 }

    View full-size slide

  270. Observable.of(1, 2, 3)
    .map(n => Observable.of(n * 2))
    .mergeAll()
    .subscribe(x => console.log(x));
    // 2
    // 4
    // 6

    View full-size slide

  271. Observable.of(1, 2, 3)
    .map(n => Observable.of(n * 2))
    .mergeAll()
    .subscribe(x => console.log(x));
    // 2
    // 4
    // 6

    View full-size slide

  272. Observable.of(1, 2, 3)
    .mergeMap(n => Observable.of(n * 2))
    .subscribe(x => console.log(x));
    // 2
    // 4
    // 6

    View full-size slide

  273. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)

    View full-size slide

  274. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    1

    View full-size slide

  275. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    1

    View full-size slide

  276. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    Observable.of(2)
    subscribe
    2

    View full-size slide

  277. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    Observable.of(2)
    subscribe
    2

    View full-size slide

  278. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    Observable.of(2)
    subscribe
    2

    View full-size slide

  279. Observable.of(1)
    .delay(1000)
    .subscribe(x => console.log(x))
    //
    // 1

    View full-size slide

  280. Observable.of(1)
    .delay(1000)
    .subscribe(x => console.log(x))
    //
    // 1

    View full-size slide

  281. Observable.of(1)
    .delay(1000)
    .subscribe(x => console.log(x))
    //
    // 1

    View full-size slide

  282. Observable.of(1)
    .delay(1000)
    .subscribe(x => console.log(x))
    //
    // 1

    View full-size slide

  283. Observable.of(1, 2, 3)
    .mergeMap(n => (
    Observable.of(n * 2).delay(1000)
    ))
    .subscribe(x => console.log(x));
    //
    // 2
    // 4
    // 6

    View full-size slide

  284. Observable.of(1, 2, 3)
    .mergeMap(n => (
    Observable.of(n * 2).delay(1000)
    ))
    .subscribe(x => console.log(x));
    //
    // 2
    // 4
    // 6

    View full-size slide

  285. Observable.of(1, 2, 3)
    .mergeMap(n => (
    Observable.of(n * 2).delay(1000)
    ))
    .subscribe(x => console.log(x));
    //
    // 2
    // 4
    // 6

    View full-size slide

  286. Observable.of(1, 2, 3)
    .mergeMap(n => (
    Observable.of(n * 2).delay(1000)
    ))
    .subscribe(x => console.log(x));
    //
    // 2
    // 4
    // 6
    ?

    View full-size slide

  287. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)

    View full-size slide

  288. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    1

    View full-size slide

  289. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    1

    View full-size slide

  290. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    2

    View full-size slide

  291. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    2
    2

    View full-size slide

  292. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    2
    2

    View full-size slide

  293. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    2
    4

    View full-size slide

  294. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    3
    2
    4

    View full-size slide

  295. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    3
    2
    4

    View full-size slide

  296. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    2
    4
    6

    View full-size slide

  297. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    2
    4
    6

    View full-size slide

  298. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    4
    6
    2

    View full-size slide

  299. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    6
    4

    View full-size slide

  300. subscribe
    mergeMap
    console.log
    Observable.of(n * 2)
    6

    View full-size slide

  301. Observable.of(1, 2, 3)
    .mergeMap(n => (
    Observable.of(n * 2).delay(1000)
    ), 1)
    .subscribe(x => console.log(x));
    //
    // 2
    //
    // 4
    //
    // 6

    View full-size slide

  302. Observable.of(1, 2, 3)
    .mergeMap(n => (
    Observable.of(n * 2).delay(1000)
    ), 1)
    .subscribe(x => console.log(x));
    //
    // 2
    //
    // 4
    //
    // 6

    View full-size slide

  303. Observable.of(1, 2, 3)
    .mergeMap(n => (
    Observable.of(n * 2).delay(1000)
    ), 1)
    .subscribe(x => console.log(x));
    //
    // 2
    //
    // 4
    //
    // 6

    View full-size slide

  304. Observable.of(1, 2, 3)
    .mergeMap(n => (
    Observable.of(n * 2).delay(1000)
    ), 1)
    .subscribe(x => console.log(x));
    //
    // 2
    //
    // 4
    //
    // 6

    View full-size slide

  305. Observable.of(1, 2, 3)
    .mergeMap(n => (
    Observable.of(n * 2).delay(1000)
    ), 1)
    .subscribe(x => console.log(x));
    //
    // 2
    //
    // 4
    //
    // 6

    View full-size slide

  306. Observable.of(1, 2, 3)
    .concatMap(n => (
    Observable.of(n * 2).delay(1000)
    ))
    .subscribe(x => console.log(x));
    //
    // 2
    //
    // 4
    //
    // 6

    View full-size slide

  307. subscribe
    concatMap
    console.log
    Observable.of(n * 2)

    View full-size slide

  308. subscribe
    console.log
    Observable.of(n * 2)
    1
    concatMap

    View full-size slide

  309. subscribe
    console.log
    Observable.of(n * 2)
    1
    concatMap

    View full-size slide

  310. subscribe
    console.log
    Observable.of(n * 2)
    2
    concatMap

    View full-size slide

  311. subscribe
    console.log
    Observable.of(n * 2)
    2
    concatMap

    View full-size slide

  312. subscribe
    console.log
    Observable.of(n * 2)
    2
    concatMap

    View full-size slide

  313. subscribe
    console.log
    Observable.of(n * 2)
    2
    concatMap

    View full-size slide

  314. subscribe
    console.log
    Observable.of(n * 2)
    2
    concatMap

    View full-size slide

  315. subscribe
    console.log
    Observable.of(n * 2)
    4
    concatMap

    View full-size slide

  316. subscribe
    console.log
    Observable.of(n * 2)
    4
    concatMap

    View full-size slide

  317. subscribe
    console.log
    Observable.of(n * 2)
    4
    concatMap

    View full-size slide

  318. subscribe
    console.log
    Observable.of(n * 2)
    3
    concatMap

    View full-size slide

  319. subscribe
    console.log
    Observable.of(n * 2)
    3
    concatMap

    View full-size slide

  320. subscribe
    console.log
    Observable.of(n * 2)
    6
    concatMap

    View full-size slide

  321. subscribe
    console.log
    Observable.of(n * 2)
    6
    concatMap

    View full-size slide

  322. subscribe
    console.log
    Observable.of(n * 2)
    6
    concatMap

    View full-size slide

  323. Rate Limiting

    View full-size slide

  324. Observable.of(1, 2, 3)
    .concatMap((id) => {
    const url = `/orders/${id}`;
    return Observable.ajax.get(url)
    .delay(1000);
    })
    .pluck('response')
    .bufferCount(3)
    .subscribe(x => console.log(x));
    // [ { id: '1', name: 'Order 1' },
    // { id: '2', name: 'Order 2' },
    // { id: '3', name: 'Order 3' } ]

    View full-size slide

  325. Observable.of(1, 2, 3)
    .concatMap((id) => {
    const url = `/orders/${id}`;
    return Observable.ajax.get(url)
    .delay(1000);
    })
    .pluck('response')
    .bufferCount(3)
    .subscribe(x => console.log(x));
    // [ { id: '1', name: 'Order 1' },
    // { id: '2', name: 'Order 2' },
    // { id: '3', name: 'Order 3' } ]

    View full-size slide

  326. Observable.of(1, 2, 3)
    .concatMap((id) => {
    const url = `/orders/${id}`;
    return Observable.ajax.get(url)
    .delay(1000);
    })
    .pluck('response')
    .bufferCount(3)
    .subscribe(x => console.log(x));
    // [ { id: '1', name: 'Order 1' },
    // { id: '2', name: 'Order 2' },
    // { id: '3', name: 'Order 3' } ]

    View full-size slide

  327. Observable.of(1, 2, 3)
    .concatMap((id) => {
    const url = `/orders/${id}`;
    return Observable.ajax.get(url)
    .delay(1000);
    })
    .pluck('response')
    .bufferCount(3)
    .subscribe(x => console.log(x));
    // [ { id: '1', name: 'Order 1' },
    // { id: '2', name: 'Order 2' },
    // { id: '3', name: 'Order 3' } ]

    View full-size slide

  328. Observable
    .ajax
    .get(url)
    subscribe
    console.log
    pluck bufferCount
    'response' 3
    concatMap

    View full-size slide

  329. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    pluck bufferCount
    'response' 3
    1

    View full-size slide

  330. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    pluck bufferCount
    'response' 3

    View full-size slide

  331. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    pluck bufferCount
    'response' 3
    R
    Rate limit next request

    View full-size slide

  332. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    pluck bufferCount
    'response' 3
    R

    View full-size slide

  333. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    pluck bufferCount
    'response' 3
    R

    View full-size slide

  334. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    pluck bufferCount
    'response' 3
    O1

    View full-size slide

  335. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    pluck bufferCount
    'response' 2
    O1

    View full-size slide

  336. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    pluck bufferCount
    'response' 2
    O1
    +

    View full-size slide

  337. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    pluck bufferCount
    'response' 1
    O1
    O2

    View full-size slide

  338. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    pluck bufferCount
    'response' 1
    O1
    O2
    +

    View full-size slide

  339. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    pluck bufferCount
    'response' 0
    O1
    O2
    O3

    View full-size slide

  340. Observable
    .ajax
    .get(url)
    subscribe
    concatMap
    console.log
    […]
    pluck bufferCount
    'response' 0

    View full-size slide

  341. Sequential vs.
    Parallel

    View full-size slide

  342. const promise = Promise.all([
    fetchOrder(1),
    fetchOrder(2),
    fetchOrder(3),
    ]);
    promise.then(x => console.log(x));
    // [ { id: '1', name: 'Order 1' },
    // { id: '2', name: 'Order 2' },
    // { id: '3', name: 'Order 3' } ]

    View full-size slide

  343. const promise = Promise.all([
    fetchOrder(1),
    fetchOrder(2),
    fetchOrder(3),
    ]);
    promise.then(x => console.log(x));
    // [ { id: '1', name: 'Order 1' },
    // { id: '2', name: 'Order 2' },
    // { id: '3', name: 'Order 3' } ]

    View full-size slide

  344. const source = Observable.forkJoin(
    fetchOrder(1),
    fetchOrder(2),
    fetchOrder(3)
    );
    source.subscribe(x => console.log(x));
    // [ { response: { id: 1, name: 'Order 1' } },
    // { response: { id: 2, name: 'Order 2' } },
    // { response: { id: 3, name: 'Order 3' } } ]

    View full-size slide

  345. const source = Observable.forkJoin(
    fetchOrder(1),
    fetchOrder(2),
    fetchOrder(3)
    );
    source.subscribe(x => console.log(x));
    // [ { response: { id: 1, name: 'Order 1' } },
    // { response: { id: 2, name: 'Order 2' } },
    // { response: { id: 3, name: 'Order 3' } } ]

    View full-size slide

  346. const source = Observable.forkJoin(
    fetchOrder(1),
    fetchOrder(2),
    fetchOrder(3)
    );
    source.subscribe(x => console.log(x));
    // [ { response: { id: 1, name: 'Order 1' } },
    // { response: { id: 2, name: 'Order 2' } },
    // { response: { id: 3, name: 'Order 3' } } ]
    Observable or
    Promise

    View full-size slide

  347. fetchOrder(1)
    fetchOrder(2)
    fetchOrder(3)
    forkJoin subscribe
    console.log

    View full-size slide

  348. fetchOrder(1)
    fetchOrder(2)
    fetchOrder(3)
    forkJoin subscribe
    console.log
    R1

    View full-size slide

  349. fetchOrder(1)
    fetchOrder(2)
    fetchOrder(3)
    forkJoin
    R1
    subscribe
    console.log

    View full-size slide

  350. fetchOrder(1)
    fetchOrder(2)
    fetchOrder(3)
    forkJoin
    R1
    subscribe
    console.log
    R3

    View full-size slide

  351. fetchOrder(1)
    fetchOrder(2)
    fetchOrder(3)
    forkJoin
    R1
    R3
    subscribe
    console.log

    View full-size slide

  352. fetchOrder(1)
    fetchOrder(2)
    fetchOrder(3)
    forkJoin
    R1
    R3
    subscribe
    console.log
    R2

    View full-size slide

  353. fetchOrder(1)
    fetchOrder(2)
    fetchOrder(3)
    forkJoin
    R1
    R2
    R3
    subscribe
    console.log

    View full-size slide

  354. fetchOrder(1)
    fetchOrder(2)
    fetchOrder(3)
    forkJoin subscribe
    console.log
    R1
    R2
    R3

    View full-size slide

  355. Tip of the iceberg

    View full-size slide

  356. • Declarative, lazy
    operations
    • Expressive event
    management
    • No more error swallowing
    • Rate limiting and
    concurrent processing

    View full-size slide

  357. • Declarative, lazy
    operations
    • Expressive event
    management
    • No more error swallowing
    • Rate limiting and
    concurrent processing




    View full-size slide

  358. github.com/ReactiveX/rxjs
    reactivex.io/rxjs
    RxJS

    View full-size slide

  359. Observables
    ECMAScript Proposal:

    github.com/tc39/proposal-observable
    Another spec implementation:

    github.com/zenparsing/zen-observable

    View full-size slide

  360. Thanks!
    Jeremy Fairbank
    @elpapapollo / jfairbank
    Slides: bit.ly/rxjs-connect

    View full-size slide