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 full-size slide

  2. Async API
    Callback

    View full-size slide

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

    View full-size slide

  4. });
    });
    });
    });
    });
    });
    Callback
    Callback
    Callback
    Callback
    Callback
    Callback

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  9. .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)

    View full-size slide

  10. Error
    Error
    Error
    Error

    View full-size slide

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

    View full-size slide

  12. Getting there…

    View full-size slide

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

    View full-size slide

  14. 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 full-size slide

  15. 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 full-size 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 full-size 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  29. 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 full-size slide

  30. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  33. Exceptional
    Situations

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  37. 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 full-size slide

  38. Error
    Error
    Error
    Error

    View full-size slide

  39. Regain Control

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  49. Order is
    important

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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




    View full-size slide

  55. Events and
    streams?

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  60. Observables
    Sequences in time
    1 2 3 4 5

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  74. Declarative
    Transformation
    Operate on events

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  92. Lazy Transformation
    Do only as much work as
    needed

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide


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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide


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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  173. Why Observables?

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  178. 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 full-size slide

  179. 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 full-size slide

  180. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  186. Cancellation

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  192. Create HTTP
    Requests

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  210. Error Handling

    View full-size slide

  211. Error
    Error
    Error
    Error
    Promises

    View full-size slide

  212. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  231. subscribe
    mergeAll
    console.log
    [3] 2

    View full-size slide

  232. subscribe
    mergeAll
    console.log
    [3] 2

    View full-size slide

  233. subscribe
    mergeAll
    console.log
    3

    View full-size slide

  234. subscribe
    mergeAll
    console.log
    3

    View full-size slide

  235. Higher Order
    Observables

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  294. Rate Limiting

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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




    View full-size slide

  314. Browser compatibility:

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

    node.green
    Async

    View full-size slide

  315. Async
    babeljs.io

    View full-size slide

  316. Observables
    github.com/ReactiveX/rxjs
    RxJS

    View full-size slide

  317. Observables
    ECMAScript Proposal:

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

    github.com/zenparsing/zen-observable

    View full-size slide

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

    View full-size slide