DevNexus 2017: The Rise of Async JavaScript

DevNexus 2017: The Rise of Async JavaScript

94bd558238b69c45d3d3e15797ae94f7?s=128

Jeremy Fairbank

February 24, 2017
Tweet

Transcript

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

  2. sigient.com

  3. None
  4. None
  5. None
  6. None
  7. “Call me maybe?”

  8. Async API Callback

  9. Callback fetchUserById(1, function(err, user) { if (err) { console.error('Could not

    retrieve user'); } else { console.log(user); } });
  10. }); }); }); }); }); }); Callback Callback Callback Callback

    Callback Callback
  11. 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); } } ); } }); }
  12. 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); } } ); } }); }
  13. 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); } } ); } }); }
  14. Async API ?

  15. Promise function fetchCustomerNameForOrder(orderId) { return fetchOrder(orderId) .then(order => fetchCustomer(order.customerId)) .then(customer

    => customer.name); }
  16. .then(...) .then(...) .then(...) .then(...) .then(...) .then(...) .then(...) .then(...)

  17. Error Error Error Error

  18. function fetchCustomerNameForOrder(orderId) { return fetchOrder(orderId) .then(order => fetchCustomer(order.customerId)) .then(customer =>

    customer.name) .catch(err => { logError(err); throw err; }); }
  19. Getting there…

  20. • More readable and maintainable • Synchronous-looking but nonblocking •

    Use native flow control constructs • More declarative and versatile
  21. 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; } }
  22. 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; } }
  23. 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; } }
  24. 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; } }
  25. Await

  26. function fetchOrder(orderId) { return fetch(`/orders/${orderId}`) .then(response => response.json()); } function

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

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

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

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

    await order
  31. await order

  32. await order

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

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

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

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

    } printOrder(1); Wrap in Promise.resolve
  37. Wrap in Promise.resolve async function printOrder(orderId) { const promise =

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

    printOrder(1); Wrap rest with then callback
  39. 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
  40. 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
  41. function fetchCustomerNameForOrder(orderId) { return Promise.resolve(fetchOrder(orderId)) .then(order => { return Promise.resolve(fetchCustomer(order.customerId))

    .then(customer => { return Promise.resolve(customer.name); }); }); } ?
  42. async function meaningOfLife() { return 42; } meaningOfLife() === 42;

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

    return Promise.resolve(42); } meaningOfLife() .then(answer => answer === 42);
  44. Exceptional Situations

  45. async function printOrder(orderId) { try { const order = await

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

    fetchOrder(orderId); console.log(order); } catch (e) { console.log('Error retrieving order', e); } } ?
  47. function fetchOrder(orderId) { return fetch(`/orders/${orderId}`) .then(resp => { if (resp.status

    === 404) { throw new Error('Order not found'); } return resp.json(); }); }
  48. 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')); } }); }); }
  49. Error Error Error Error

  50. Regain Control

  51. async function findOrCreateOrder(orderId) { let order; if (await orderExists(orderId)) {

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

    order = await fetchOrder(orderId); } else { order = await createOrder(); } return order; }
  53. async function printOrders(orderIds) { for (const id of orderIds) {

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

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

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

    const order = await fetchOrder(id); console.log(order); } } printOrders([1, 2, 3]);
  57. printOrders([1, 2, 3]); await fetchOrder(1); await fetchOrder(2); await fetchOrder(3);

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

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

  60. Order is important

  61. async function printOrders(orderIds) { const orders = await Promise.all( orderIds.map(fetchOrder)

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

    ); orders.forEach(order => console.log(order)); }
  63. printOrders([1, 2, 3]); await Promise.all([ fetchOrder(1), fetchOrder(2), fetchOrder(3) ]);

  64. printOrders([1, 2, 3]); Demo rise.of.async.jeremyfairbank.com

  65. • Readable, synchronous- like code • Native flow control constructs

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

    • Sequential and concurrent processing ✓ ✓ ✓ ✓
  67. Events and streams?

  68. let counter = 0; function updateCounter(n) { counter += n;

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

    counterEl.innerHTML = counter; } incrementBtn.addEventListener('click', () => { updateCounter(1); }); decrementBtn.addEventListener('click', () => { updateCounter(-1); }); ×
  70. let counter = 0; async function listenIncrement() { await click(incrementBtn);

    counter += 1; counterEl.innerHTML = counter; listenIncrement(); }
  71. let counter = 0; async function listenIncrement() { await click(incrementBtn);

    counter += 1; counterEl.innerHTML = counter; listenIncrement(); }
  72. let counter = 0; async function listenIncrement() { await click(incrementBtn);

    counter += 1; counterEl.innerHTML = counter; listenIncrement(); }
  73. let counter = 0; async function listenIncrement() { await click(incrementBtn);

    counter += 1; counterEl.innerHTML = counter; listenIncrement(); }
  74. let counter = 0; async function listenIncrement() { await click(incrementBtn);

    counter += 1; counterEl.innerHTML = counter; listenIncrement(); } ×
  75. 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; });
  76. RxJS

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

    space
  78. Observables Sequences in time 1 2 3 4 5

  79. Reactive

  80. Reactive 3

  81. const { Observable } = require('rxjs'); const source = Observable.of(1,

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

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

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

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

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

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

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

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

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

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

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

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

  94. Declarative Transformation Operate on events

  95. Observable.of(1, 2, 3) .map(n => n * 2) .subscribe(x =>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  112. Lazy Transformation Do only as much work as needed

  113. Observable.range(1, 100) .map(n => n * 2) .filter(n => n

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

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

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

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

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

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

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

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

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

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

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

    100) filter 2 take
  125. console.log n * 2 map subscribe n > 4 2

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

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

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

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

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

    100) filter 2 take
  131. console.log n * 2 map subscribe n > 4 3

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

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

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

    100) filter 2 take 6
  135. ✓ console.log n * 2 map subscribe n > 4

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

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

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

    100) filter 1 take
  139. console.log n * 2 map subscribe n > 4 4

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

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

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

    100) filter 1 take 8
  143. ✓ console.log n * 2 map subscribe n > 4

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

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

    100) filter 0 take 8
  146. DOM Events

  147. Observable.fromEvent(incrementBtn, 'click') .mapTo(1) .scan((acc, curr) => acc + curr, 0)

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

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

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

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

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

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

    .subscribe((counter) => { counterEl.innerHTML = counter; });
  154. .scan((acc, curr) => acc + curr, 0) Accumulated counter value

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

    (1)
  156. .scan((acc, curr) => acc + curr, 0) Return new accumulated

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

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

    scan
  159. acc + curr 1 mapTo subscribe e scan 0 counterEl.innerHTML

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

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

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

    = counter
  163. 1 mapTo subscribe scan 1 acc + curr 1 Counter

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

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

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

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

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

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

    = counter
  170. 1 mapTo subscribe scan 2 acc + curr 2 Counter

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

    = counter
  172. 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; });
  173. 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; });
  174. 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; });
  175. 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; });
  176. acc + curr 1 mapTo subscribe 0 scan -1 mapTo

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

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

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

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

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

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

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

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

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

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

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

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

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

    Increment Decrement 0 counterEl.innerHTML = counter
  190. Async HTTP

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

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

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

    });
  194. Why Observables?

  195. 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)); });
  196. 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)); });
  197. 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)); });
  198. 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)); });
  199. 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)); }
  200. 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)); }
  201. 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)); }
  202. fetchOrders() .mergeAll() .filter( order => order.customerName === 'Tucker' ) .map(order

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

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

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

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

    => order.id) .subscribe(id => console.log(id)); Observable
  207. Cancellation

  208. const promise = fetchOrders() .then((orders) => { orders.foreach((order) => {

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

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

    console.log(order); }); }); promise.cancel(); Promise ×
  211. Observable const subscription = fetchOrders() .subscribe((orders) => { orders.forEach((order) =>

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

    { console.log(order); }); }); subscription.unsubscribe();
  213. console.log subscribe fetchOrders() .subscribe(...)

  214. console.log subscribe fetchOrders() .subscribe(...)

  215. subscription.unsubscribe(); console.log subscribe × fetchOrders() .subscribe(...) ×

  216. Create HTTP Requests

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

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

  219. function fetchOrders() { return Observable.create((subscriber) => { fetchOrdersFromDb((orders) => {

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

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

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

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

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

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

    subscriber.next(orders); subscriber.complete(); }); }); } Custom Observable Creation ?
  226. Observable.of(1, 2, 3) .subscribe(x => console.log(x));

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

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

  229. Observable.of(1, 2, 3) .subscribe({ next: x => console.log(x), complete: ()

    => console.log('Done!'), }); // 1 // 2 // 3 // Done!
  230. function fetchOrders() { return Observable.create((subscriber) => { fetchOrdersFromDb((orders) => {

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

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

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

    subscriber.next(orders); subscriber.complete(); }); }); } fetchOrders().mergeAll() .subscribe(x => console.log(x));
  234. function fetchOrders() { return Observable.create((subscriber) => { fetchOrdersFromDb((orders) => {

    subscriber.next(orders); subscriber.complete(); }); }); } fetchOrders().mergeAll() .subscribe(x => console.log(x)); No complete callback
  235. function fetchOrders() { return Observable.create((subscriber) => { fetchOrdersFromDb((orders) => {

    subscriber.next(orders); subscriber.complete(); }); }); } fetchOrders().mergeAll() .subscribe(x => console.log(x)); Safe No complete callback
  236. 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
  237. 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
  238. 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
  239. 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
  240. Error Handling

  241. Error Error Error Error Promises

  242. 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), });
  243. const source = Observable.create((subscriber) => { subscriber.next(1); subscriber.error(new Error('Uh oh'));

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

    subscriber.next(2); }); source.subscribe(x => console.log(x));
  245. fetchOrders() .catch((e) => { logError(e); return Observable.of([]); }) .subscribe(x =>

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

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

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

    console.log(x));
  249. fetchOrders() .catch((e) => { logError(e); return legacyFetchOrders() .catch((e2) => {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  268. Clean Up

  269. function fetchOrdersStream() { return Observable.create((subscriber) => { const socket =

    new WebSocket('ws://example.com'); socket.addEventListener('message', (event) => { subscriber.next(event.data); }); return () => { socket.close(); }; }); }
  270. function fetchOrdersStream() { return Observable.create((subscriber) => { const socket =

    new WebSocket('ws://example.com'); socket.addEventListener('message', (event) => { subscriber.next(event.data); }); return () => { socket.close(); }; }); }
  271. function fetchOrdersStream() { return Observable.create((subscriber) => { const socket =

    new WebSocket('ws://example.com'); socket.addEventListener('message', (event) => { subscriber.next(event.data); }); return () => { socket.close(); }; }); }
  272. function fetchOrdersStream() { return Observable.create((subscriber) => { const socket =

    new WebSocket('ws://example.com'); socket.addEventListener('message', (event) => { subscriber.next(event.data); }); return () => { socket.close(); }; }); } Called when subscription unsubscribes
  273. function fetchOrdersStream() { return Observable.create((subscriber) => { const socket =

    new WebSocket('ws://example.com'); socket.addEventListener('message', (event) => { subscriber.next(event.data); }); return () => { socket.close(); }; }); } Close socket, deallocate resources, etc.
  274. Lazy Subscriptions

  275. const p1 = fetchOrders(); const p2 = fetchOrders(); const p3

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

    = fetchOrders(); Promises Immediate
  277. Observables const o1 = fetchOrders(); const o2 = fetchOrders(); const

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

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

    const o3 = fetchOrders(); o1.subscribe(); o2.subscribe(); o3.subscribe(); Issue Request
  280. const o1 = fetchOrders(); o1.subscribe(); o1.subscribe(); o1.subscribe();

  281. const o1 = fetchOrders(); o1.subscribe(); o1.subscribe(); o1.subscribe(); Pure

  282. const o1 = fetchOrders(); o1.subscribe(); o1.subscribe(); o1.subscribe(); Side Effects Pure

  283. Hot Cold vs.

  284. Observable creates the source Cold

  285. Best for one-off unique requests. Cold

  286. function fetchOrders() { return Observable.create((subscriber) => { fetchOrdersFromDb((orders) => {

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

    subscriber.next(orders); subscriber.complete(); }); }); } Resource requested/created at subscription time
  288. Hot Observable closes over the source

  289. Hot Best for multicasting and sharing resources.

  290. const socket = new WebSocket('ws://example.com'); const stream = Observable.create((subscriber) =>

    { socket.addEventListener('message', (event) => { subscriber.next(event.data); }); });
  291. const socket = new WebSocket('ws://example.com'); const stream = Observable.create((subscriber) =>

    { socket.addEventListener('message', (event) => { subscriber.next(event.data); }); }); Resource created outside subscription
  292. const socket = new WebSocket('ws://example.com'); const stream = Observable.create((subscriber) =>

    { socket.addEventListener('message', (event) => { subscriber.next(event.data); }); }); Close over existing resource when subscribing
  293. const sub1 = stream.subscribe(x => console.log(x)); const sub2 = stream.subscribe(x

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

    => console.log(x)); Shared stream of data
  295. fetchOrders() .mergeAll() .filter( order => order.customerName === 'Tucker' ) .map(order

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

    => order.id) .subscribe(id => console.log(id)); ? Recall
  297. Observable.of([1, 2, 3]) .subscribe(x => console.log(x)); // [ 1, 2,

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

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

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

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

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

    2 // 3
  303. subscribe mergeAll console.log [1, 2, 3]

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

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

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

  307. subscribe mergeAll console.log [3] 2

  308. subscribe mergeAll console.log [3] 2

  309. subscribe mergeAll console.log 3

  310. subscribe mergeAll console.log 3

  311. Higher Order Observables

  312. Observable.of(1, 2, 3) .map(n => n * 2) .subscribe(x =>

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

    console.log(x)); // 2 // 4 // 6 Delay?
  314. 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 }
  315. 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 }
  316. 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 }
  317. Observable.of(1, 2, 3) .map(n => Observable.of(n * 2)) .mergeAll() .subscribe(x

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

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

    console.log(x)); // 2 // 4 // 6
  320. subscribe mergeMap console.log Observable.of(n * 2)

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

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

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

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

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

  326. Observable.of(1) .delay(1000) .subscribe(x => console.log(x)) // <tick> // 1

  327. Observable.of(1) .delay(1000) .subscribe(x => console.log(x)) // <tick> // 1

  328. Observable.of(1) .delay(1000) .subscribe(x => console.log(x)) // <tick> // 1

  329. Observable.of(1) .delay(1000) .subscribe(x => console.log(x)) // <tick> // 1

  330. Observable.of(1, 2, 3) .mergeMap(n => ( Observable.of(n * 2).delay(1000) ))

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

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

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

    .subscribe(x => console.log(x)); // <tick> // 2 // 4 // 6 ?
  334. Concurrency

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  349. Observable.of(1, 2, 3) .mergeMap(n => ( Observable.of(n * 2).delay(1000) ),

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

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

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

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

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

    .subscribe(x => console.log(x)); // <tick> // 2 // <tick> // 4 // <tick> // 6
  355. subscribe concatMap console.log Observable.of(n * 2)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  371. Rate Limiting

  372. 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' } ]
  373. 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' } ]
  374. 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' } ]
  375. 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' } ]
  376. Observable .ajax .get(url) subscribe console.log pluck bufferCount 'response' 3 concatMap

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

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

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

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

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

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

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

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

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

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

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

    O1 O2 O3
  388. Observable .ajax .get(url) subscribe concatMap console.log […] pluck bufferCount 'response'

    0
  389. Sequential vs. Parallel

  390. const promise = Promise.all([ fetchOrder(1), fetchOrder(2), fetchOrder(3), ]); promise.then(x =>

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

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

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

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

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

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

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

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

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

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

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

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

  403. • Declarative, lazy operations • Expressive event management • No

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

    more error swallowing • Rate limiting and concurrent processing ✓ ✓ ✓ ✓
  405. Resources

  406. Browser compatibility:
 kangax.github.io/compat-table/es2016plus Node compatibility:
 node.green Async

  407. Async babeljs.io

  408. Observables github.com/ReactiveX/rxjs RxJS

  409. Observables ECMAScript Proposal:
 github.com/tc39/proposal-observable Another spec implementation:
 github.com/zenparsing/zen-observable

  410. THANKS! Jeremy Fairbank blog.jeremyfairbank.com @elpapapollo | gh/jfairbank bit.ly/devnexus-rise-of-async SLIDES: github.com/jfairbank/rise-of-async-js-talk

    CODE: