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

JazzCon 2017: The Rise of Async JavaScript

JazzCon 2017: The Rise of Async JavaScript

Jeremy Fairbank

March 23, 2017
Tweet

More Decks by Jeremy Fairbank

Other Decks in Programming

Transcript

  1. the RISEof async
    JavaScript
    Jeremy Fairbank
    @elpapapollo | gh/jfairbank

    View Slide

  2. sigient.com

    View Slide

  3. Async API
    Callback

    View Slide

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

    View Slide

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

    View 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 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. Async API ?

    View Slide

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

    View Slide

  11. .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)

    View Slide

  12. Error
    Error
    Error
    Error

    View Slide

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

    View Slide

  14. Getting there…

    View Slide

  15. • More readable and
    maintainable
    • Synchronous-looking but
    nonblocking
    • Use native flow control
    constructs
    • More declarative and
    versatile

    View Slide

  16. async function fetchCustomerNameForOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    const customer = await fetchCustomer(order.customerId);
    return customer.name;
    } catch (err) {
    logError(err);
    throw err;
    }
    }

    View Slide

  17. async function fetchCustomerNameForOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    const customer = await fetchCustomer(order.customerId);
    return customer.name;
    } catch (err) {
    logError(err);
    throw err;
    }
    }

    View Slide

  18. async function fetchCustomerNameForOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    const customer = await fetchCustomer(order.customerId);
    return customer.name;
    } catch (err) {
    logError(err);
    throw err;
    }
    }

    View Slide

  19. async function fetchCustomerNameForOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    const customer = await fetchCustomer(order.customerId);
    return customer.name;
    } catch (err) {
    logError(err);
    throw err;
    }
    }

    View Slide

  20. Await

    View Slide

  21. function fetchOrder(orderId) {
    return fetch(`/orders/${orderId}`)
    .then(response => response.json());
    }
    function printOrder(orderId) {
    fetchOrder(orderId)
    .then(order => console.log(order));
    }

    View Slide

  22. function fetchOrder(orderId) {
    return fetch(`/orders/${orderId}`)
    .then(response => response.json());
    }
    async function printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }

    View Slide

  23. async printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    fetchOrder(orderId) order

    View Slide

  24. async printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    await

    View Slide

  25. async printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    await order

    View Slide

  26. await order

    View Slide

  27. await order

    View Slide

  28. async printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    } ?

    View Slide

  29. async function printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    printOrder(1);
    Invoke

    View Slide

  30. async function printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    printOrder(1);
    Encounter await

    View Slide

  31. async function printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    printOrder(1);
    Wrap in Promise.resolve

    View Slide

  32. Wrap in Promise.resolve
    async function printOrder(orderId) {
    const promise = Promise.resolve(fetchOrder(orderId));
    console.log(order);
    }
    printOrder(1);

    View Slide

  33. async function printOrder(orderId) {
    const promise = Promise.resolve(fetchOrder(orderId));
    console.log(order);
    }
    printOrder(1);
    Wrap rest with then callback

    View Slide

  34. async function printOrder(orderId) {
    const promise = Promise.resolve(fetchOrder(orderId));
    return promise.then(order => {
    console.log(order);
    return Promise.resolve(undefined);
    });
    }
    printOrder(1);
    Wrap rest with then callback

    View Slide

  35. async function printOrder(orderId) {
    const promise = Promise.resolve(fetchOrder(orderId));
    return promise.then(order => {
    console.log(order);
    return Promise.resolve(undefined);
    });
    }
    printOrder(1);
    Wrap implicit return with
    Promise.resolve

    View Slide

  36. async function meaningOfLife() {
    return 42;
    }
    meaningOfLife() === 42;
    ???

    View Slide

  37. async function meaningOfLife() {
    return 42;
    }
    function meaningOfLife() {
    return Promise.resolve(42);
    }
    meaningOfLife()
    .then(answer => answer === 42);

    View Slide

  38. Exceptional
    Situations

    View Slide

  39. async function printOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    console.log(order);
    } catch (e) {
    console.log('Error retrieving order', e);
    }
    }

    View Slide

  40. async function printOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    console.log(order);
    } catch (e) {
    console.log('Error retrieving order', e);
    }
    } ?

    View Slide

  41. function fetchOrder(orderId) {
    return fetch(`/orders/${orderId}`)
    .then(resp => {
    if (resp.status === 404) {
    throw new Error('Order not found');
    }
    return resp.json();
    });
    }

    View Slide

  42. function fetchOrder(orderId) {
    return new Promise((resolve, reject) => {
    $.get(`/orders/${orderId}`)
    .done(order => resolve(order))
    .fail(resp => {
    if (resp.status === 404) {
    reject(new Error('Order not found'));
    }
    });
    });
    }

    View Slide

  43. Error
    Error
    Error
    Error

    View Slide

  44. Regain Control

    View Slide

  45. async function findOrCreateOrder(orderId) {
    let order;
    if (await orderExists(orderId)) {
    order = await fetchOrder(orderId);
    } else {
    order = await createOrder();
    }
    return order;
    }

    View Slide

  46. async function findOrCreateOrder(orderId) {
    let order;
    if (await orderExists(orderId)) {
    order = await fetchOrder(orderId);
    } else {
    order = await createOrder();
    }
    return order;
    }

    View Slide

  47. async function printOrders(orderIds) {
    for (const id of orderIds) {
    const order = await fetchOrder(id);
    console.log(order);
    }
    }

    View Slide

  48. async function printOrders(orderIds) {
    for (const id of orderIds) {
    const order = await fetchOrder(id);
    console.log(order);
    }
    }

    View Slide

  49. async function printOrders(orderIds) {
    for (const id of orderIds) {
    const order = await fetchOrder(id);
    console.log(order);
    }
    } Problem?

    View Slide

  50. async function printOrders(orderIds) {
    for (const id of orderIds) {
    const order = await fetchOrder(id);
    console.log(order);
    }
    }
    printOrders([1, 2, 3]);

    View Slide

  51. printOrders([1, 2, 3]);
    await fetchOrder(1);
    await fetchOrder(2);
    await fetchOrder(3);

    View Slide

  52. printOrders([1, 2, 3]);
    await fetchOrder(1);
    await fetchOrder(2);
    await fetchOrder(3);

    View Slide

  53. printOrders([1, 2, 3]);
    await fetchOrder(1);
    await fetchOrder(2);
    await fetchOrder(3);

    View Slide

  54. Order is
    important

    View Slide

  55. async function printOrders(orderIds) {
    const orders = await Promise.all(
    orderIds.map(fetchOrder)
    );
    orders.forEach(order => console.log(order));
    }

    View Slide

  56. async function printOrders(orderIds) {
    const orders = await Promise.all(
    orderIds.map(fetchOrder)
    );
    orders.forEach(order => console.log(order));
    }

    View Slide

  57. printOrders([1, 2, 3]);
    await Promise.all([
    fetchOrder(1),
    fetchOrder(2),
    fetchOrder(3)
    ]);

    View Slide

  58. • Readable, synchronous-
    like code
    • Native flow control
    constructs
    • Sequential and
    concurrent processing

    View Slide

  59. • Readable, synchronous-
    like code
    • Native flow control
    constructs
    • Sequential and
    concurrent processing




    View Slide

  60. Events and
    streams?

    View Slide

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

    View Slide

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

    View Slide

  63. 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

  64. RxJS

    View Slide

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

    View Slide

  66. Observables
    Sequences in time
    1 2 3 4 5

    View Slide

  67. Reactive

    View Slide

  68. Reactive
    3

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  82. Declarative
    Transformation
    Operate on events

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  100. Lazy Transformation
    Do only as much work as
    needed

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide


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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide


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

    View Slide

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

    View Slide

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

    View Slide

  134. DOM Events

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  160. 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

  161. 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

  162. 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

  163. 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

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  178. Async HTTP

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  182. Observable
    fetchOrders()
    .subscribe((orders) => {
    orders.forEach((order) => {
    console.log(order);
    });
    });
    Lazy unlike Promise

    View Slide

  183. Why Observables?

    View Slide

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

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

  186. 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

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

  188. Async
    async function printCustomerNames() {
    const orders = await fetchOrders();
    const filtered = orders.filter(
    order => order.customerName === 'Tucker'
    );
    const orderIds = filtered.map(order => order.id);
    orderIds.forEach(id => console.log(id));
    }

    View Slide

  189. Async
    async function printCustomerNames() {
    const orders = await fetchOrders();
    const filtered = orders.filter(
    order => order.customerName === 'Tucker'
    );
    const orderIds = filtered.map(order => order.id);
    orderIds.forEach(id => console.log(id));
    }

    View Slide

  190. Async
    async function printCustomerNames() {
    const orders = await fetchOrders();
    const filtered = orders.filter(
    order => order.customerName === 'Tucker'
    );
    const orderIds = filtered.map(order => order.id);
    orderIds.forEach(id => console.log(id));
    }

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  196. Cancellation

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  202. Create HTTP
    Requests

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

  217. 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

  218. 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

  219. 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

  220. Error Handling

    View Slide

  221. Error
    Error
    Error
    Error
    Promises

    View Slide

  222. 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),
    });

    View Slide

  223. const source = Observable.create((subscriber) => {
    subscriber.next(1);
    subscriber.error(new Error('Uh oh'));
    subscriber.next(2);
    });
    source.subscribe(x => console.log(x));
    ?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  241. subscribe
    mergeAll
    console.log
    [3] 2

    View Slide

  242. subscribe
    mergeAll
    console.log
    [3] 2

    View Slide

  243. subscribe
    mergeAll
    console.log
    3

    View Slide

  244. subscribe
    mergeAll
    console.log
    3

    View Slide

  245. Higher Order
    Observables

    View Slide

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

    View Slide

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

    View Slide

  248. 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

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

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

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  268. Concurrency

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  305. Rate Limiting

    View Slide

  306. 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

  307. 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

  308. 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

  309. 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

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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




    View Slide

  325. Resources

    View Slide

  326. Browser compatibility:

    kangax.github.io/compat-table/es2016plus
    Node compatibility:

    node.green
    Async

    View Slide

  327. Async
    babeljs.io

    View Slide

  328. Observables
    github.com/ReactiveX/rxjs
    RxJS

    View Slide

  329. Observables
    ECMAScript Proposal:

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

    github.com/zenparsing/zen-observable

    View Slide

  330. THANKS!
    bit.ly/jazzcon-rise-of-async
    SLIDES:
    github.com/jfairbank/rise-of-async-js-talk
    CODE:
    Jeremy Fairbank
    @elpapapollo | gh/jfairbank

    View Slide