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 Slide

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

    View Slide

  3. Async

    View Slide

  4. Async API
    Callback

    View Slide

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

    View Slide

  6. });
    });
    });
    });
    });
    });
    Callback
    Callback
    Callback
    Callback
    Callback
    Callback

    View 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 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 Slide

  9. 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 Slide

  10. Async API ?

    View Slide

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

    View Slide

  12. .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)

    View Slide

  13. Error
    Error
    Error
    Error

    View Slide

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

    View Slide

  15. Getting there…

    View Slide

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

    View Slide

  17. RxJS
    Observables

    View Slide

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

    View Slide

  19. Observables
    Sequences in time
    1 2 3 4 5

    View Slide

  20. Reactive

    View Slide

  21. Reactive
    3

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  35. Declarative
    Transformation
    Operate on events

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  53. Lazy Transformation
    Do only as much work as
    needed

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide


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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide


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

    View Slide

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

    View Slide

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

    View Slide

  87. DOM Events

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  115. 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 Slide

  116. 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 Slide

  117. 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 Slide

  118. 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 Slide

  119. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  134. Async HTTP

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  138. Why Observables?

    View Slide

  139. 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 Slide

  140. 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 Slide

  141. 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 Slide

  142. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  148. Cancellation

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  154. Lazy
    Subscriptions

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  163. Create HTTP
    Requests

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  177. 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 Slide

  178. 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 Slide

  179. 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 Slide

  180. Error Handling

    View Slide

  181. 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 Slide

  182. 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 Slide

  183. 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 Slide

  184. 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 Slide

  185. 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 Slide

  186. Error
    Error
    Error
    Error
    Promises

    View Slide

  187. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  207. Hot Cold
    vs.

    View Slide

  208. Observable
    creates the source
    Cold

    View Slide

  209. Best for one-off
    unique requests.
    Cold

    View Slide

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

    View Slide

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

    View Slide

  212. WebSockets

    View Slide

  213. 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 Slide

  214. 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 Slide

  215. 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 Slide

  216. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  223. View Slide

  224. .subscribe(...)

    View Slide

  225. .subscribe(...) .subscribe(...)

    View Slide

  226. .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View Slide

  227. .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View Slide

  228. .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View Slide

  229. .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View Slide

  230. .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View Slide

  231. .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)
    .subscribe(...)

    View Slide

  232. Hot
    Observable
    closes over the source

    View Slide

  233. Hot
    Best for multicasting
    and sharing resources.

    View Slide

  234. 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 Slide

  235. 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 Slide

  236. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  249. 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 Slide

  250. 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 Slide

  251. 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 Slide

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

    View Slide

  253. 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 Slide

  254. Clean Up

    View Slide

  255. 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 Slide

  256. 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 Slide

  257. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  270. subscribe
    mergeAll
    console.log
    [3] 2

    View Slide

  271. subscribe
    mergeAll
    console.log
    [3] 2

    View Slide

  272. subscribe
    mergeAll
    console.log
    3

    View Slide

  273. subscribe
    mergeAll
    console.log
    3

    View Slide

  274. Higher Order
    Observables

    View Slide

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

    View Slide

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

    View Slide

  277. 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 Slide

  278. 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 Slide

  279. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  297. Concurrency

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  334. Rate Limiting

    View Slide

  335. 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 Slide

  336. 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 Slide

  337. 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 Slide

  338. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  352. Sequential vs.
    Parallel

    View Slide

  353. 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 Slide

  354. 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 Slide

  355. 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 Slide

  356. 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 Slide

  357. 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  366. Tip of the iceberg

    View Slide

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

    View Slide

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




    View Slide

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

    View Slide

  370. Observables
    ECMAScript Proposal:

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

    github.com/zenparsing/zen-observable

    View Slide

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

    View Slide