Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

sigient.com

Slide 3

Slide 3 text

Async API Callback

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

}); }); }); }); }); }); Callback Callback Callback Callback Callback Callback

Slide 6

Slide 6 text

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); } } ); } }); }

Slide 7

Slide 7 text

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); } } ); } }); }

Slide 8

Slide 8 text

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); } } ); } }); }

Slide 9

Slide 9 text

Async API ?

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

Error Error Error Error

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

Getting there…

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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; } }

Slide 17

Slide 17 text

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; } }

Slide 18

Slide 18 text

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; } }

Slide 19

Slide 19 text

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; } }

Slide 20

Slide 20 text

Await

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

await order

Slide 27

Slide 27 text

await order

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Exceptional Situations

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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')); } }); }); }

Slide 43

Slide 43 text

Error Error Error Error

Slide 44

Slide 44 text

Regain Control

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

Order is important

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

Events and streams?

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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; });

Slide 64

Slide 64 text

RxJS

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

Observables Sequences in time 1 2 3 4 5

Slide 67

Slide 67 text

Reactive

Slide 68

Slide 68 text

Reactive 3

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

Declarative Transformation Operate on events

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

Lazy Transformation Do only as much work as needed

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

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

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

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

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

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

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

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

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

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

Slide 121

Slide 121 text

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

Slide 122

Slide 122 text

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

Slide 123

Slide 123 text

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

Slide 124

Slide 124 text

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

Slide 125

Slide 125 text

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

Slide 126

Slide 126 text

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

Slide 127

Slide 127 text

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

Slide 128

Slide 128 text

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

Slide 129

Slide 129 text

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

Slide 130

Slide 130 text

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

Slide 131

Slide 131 text

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

Slide 132

Slide 132 text

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

Slide 133

Slide 133 text

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

Slide 134

Slide 134 text

DOM Events

Slide 135

Slide 135 text

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

Slide 136

Slide 136 text

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

Slide 137

Slide 137 text

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

Slide 138

Slide 138 text

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

Slide 139

Slide 139 text

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

Slide 140

Slide 140 text

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

Slide 141

Slide 141 text

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

Slide 142

Slide 142 text

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

Slide 143

Slide 143 text

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

Slide 144

Slide 144 text

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

Slide 145

Slide 145 text

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

Slide 146

Slide 146 text

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

Slide 147

Slide 147 text

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

Slide 148

Slide 148 text

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

Slide 149

Slide 149 text

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

Slide 150

Slide 150 text

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

Slide 151

Slide 151 text

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

Slide 152

Slide 152 text

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

Slide 153

Slide 153 text

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

Slide 154

Slide 154 text

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

Slide 155

Slide 155 text

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

Slide 156

Slide 156 text

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

Slide 157

Slide 157 text

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

Slide 158

Slide 158 text

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

Slide 159

Slide 159 text

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

Slide 160

Slide 160 text

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; });

Slide 161

Slide 161 text

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; });

Slide 162

Slide 162 text

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; });

Slide 163

Slide 163 text

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; });

Slide 164

Slide 164 text

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

Slide 165

Slide 165 text

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

Slide 166

Slide 166 text

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

Slide 167

Slide 167 text

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

Slide 168

Slide 168 text

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

Slide 169

Slide 169 text

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

Slide 170

Slide 170 text

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

Slide 171

Slide 171 text

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

Slide 172

Slide 172 text

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

Slide 173

Slide 173 text

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

Slide 174

Slide 174 text

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

Slide 175

Slide 175 text

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

Slide 176

Slide 176 text

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

Slide 177

Slide 177 text

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

Slide 178

Slide 178 text

Async HTTP

Slide 179

Slide 179 text

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

Slide 180

Slide 180 text

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

Slide 181

Slide 181 text

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

Slide 182

Slide 182 text

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

Slide 183

Slide 183 text

Why Observables?

Slide 184

Slide 184 text

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)); });

Slide 185

Slide 185 text

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)); });

Slide 186

Slide 186 text

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)); });

Slide 187

Slide 187 text

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)); });

Slide 188

Slide 188 text

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)); }

Slide 189

Slide 189 text

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)); }

Slide 190

Slide 190 text

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)); }

Slide 191

Slide 191 text

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

Slide 192

Slide 192 text

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

Slide 193

Slide 193 text

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

Slide 194

Slide 194 text

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

Slide 195

Slide 195 text

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

Slide 196

Slide 196 text

Cancellation

Slide 197

Slide 197 text

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

Slide 198

Slide 198 text

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

Slide 199

Slide 199 text

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

Slide 200

Slide 200 text

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

Slide 201

Slide 201 text

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

Slide 202

Slide 202 text

Create HTTP Requests

Slide 203

Slide 203 text

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

Slide 204

Slide 204 text

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

Slide 205

Slide 205 text

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

Slide 206

Slide 206 text

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

Slide 207

Slide 207 text

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

Slide 208

Slide 208 text

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

Slide 209

Slide 209 text

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

Slide 210

Slide 210 text

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

Slide 211

Slide 211 text

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

Slide 212

Slide 212 text

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

Slide 213

Slide 213 text

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

Slide 214

Slide 214 text

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

Slide 215

Slide 215 text

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

Slide 216

Slide 216 text

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

Slide 217

Slide 217 text

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

Slide 218

Slide 218 text

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

Slide 219

Slide 219 text

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

Slide 220

Slide 220 text

Error Handling

Slide 221

Slide 221 text

Error Error Error Error Promises

Slide 222

Slide 222 text

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

Slide 223

Slide 223 text

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

Slide 224

Slide 224 text

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

Slide 225

Slide 225 text

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

Slide 226

Slide 226 text

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

Slide 227

Slide 227 text

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

Slide 228

Slide 228 text

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

Slide 229

Slide 229 text

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

Slide 230

Slide 230 text

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

Slide 231

Slide 231 text

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

Slide 232

Slide 232 text

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

Slide 233

Slide 233 text

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

Slide 234

Slide 234 text

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

Slide 235

Slide 235 text

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

Slide 236

Slide 236 text

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

Slide 237

Slide 237 text

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

Slide 238

Slide 238 text

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

Slide 239

Slide 239 text

subscribe mergeAll console.log [2, 3] 1

Slide 240

Slide 240 text

subscribe mergeAll console.log [2, 3] 1

Slide 241

Slide 241 text

subscribe mergeAll console.log [3] 2

Slide 242

Slide 242 text

subscribe mergeAll console.log [3] 2

Slide 243

Slide 243 text

subscribe mergeAll console.log 3

Slide 244

Slide 244 text

subscribe mergeAll console.log 3

Slide 245

Slide 245 text

Higher Order Observables

Slide 246

Slide 246 text

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

Slide 247

Slide 247 text

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

Slide 248

Slide 248 text

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 }

Slide 249

Slide 249 text

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 }

Slide 250

Slide 250 text

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 }

Slide 251

Slide 251 text

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

Slide 252

Slide 252 text

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

Slide 253

Slide 253 text

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

Slide 254

Slide 254 text

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

Slide 255

Slide 255 text

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

Slide 256

Slide 256 text

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

Slide 257

Slide 257 text

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

Slide 258

Slide 258 text

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

Slide 259

Slide 259 text

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

Slide 260

Slide 260 text

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

Slide 261

Slide 261 text

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

Slide 262

Slide 262 text

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

Slide 263

Slide 263 text

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

Slide 264

Slide 264 text

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

Slide 265

Slide 265 text

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

Slide 266

Slide 266 text

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

Slide 267

Slide 267 text

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

Slide 268

Slide 268 text

Concurrency

Slide 269

Slide 269 text

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

Slide 270

Slide 270 text

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

Slide 271

Slide 271 text

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

Slide 272

Slide 272 text

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

Slide 273

Slide 273 text

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

Slide 274

Slide 274 text

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

Slide 275

Slide 275 text

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

Slide 276

Slide 276 text

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

Slide 277

Slide 277 text

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

Slide 278

Slide 278 text

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

Slide 279

Slide 279 text

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

Slide 280

Slide 280 text

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

Slide 281

Slide 281 text

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

Slide 282

Slide 282 text

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

Slide 283

Slide 283 text

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

Slide 284

Slide 284 text

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

Slide 285

Slide 285 text

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

Slide 286

Slide 286 text

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

Slide 287

Slide 287 text

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

Slide 288

Slide 288 text

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

Slide 289

Slide 289 text

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

Slide 290

Slide 290 text

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

Slide 291

Slide 291 text

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

Slide 292

Slide 292 text

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

Slide 293

Slide 293 text

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

Slide 294

Slide 294 text

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

Slide 295

Slide 295 text

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

Slide 296

Slide 296 text

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

Slide 297

Slide 297 text

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

Slide 298

Slide 298 text

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

Slide 299

Slide 299 text

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

Slide 300

Slide 300 text

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

Slide 301

Slide 301 text

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

Slide 302

Slide 302 text

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

Slide 303

Slide 303 text

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

Slide 304

Slide 304 text

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

Slide 305

Slide 305 text

Rate Limiting

Slide 306

Slide 306 text

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' } ]

Slide 307

Slide 307 text

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' } ]

Slide 308

Slide 308 text

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' } ]

Slide 309

Slide 309 text

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' } ]

Slide 310

Slide 310 text

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

Slide 311

Slide 311 text

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

Slide 312

Slide 312 text

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

Slide 313

Slide 313 text

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

Slide 314

Slide 314 text

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

Slide 315

Slide 315 text

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

Slide 316

Slide 316 text

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

Slide 317

Slide 317 text

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

Slide 318

Slide 318 text

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

Slide 319

Slide 319 text

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

Slide 320

Slide 320 text

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

Slide 321

Slide 321 text

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

Slide 322

Slide 322 text

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

Slide 323

Slide 323 text

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

Slide 324

Slide 324 text

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

Slide 325

Slide 325 text

Resources

Slide 326

Slide 326 text

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

Slide 327

Slide 327 text

Async babeljs.io

Slide 328

Slide 328 text

Observables github.com/ReactiveX/rxjs RxJS

Slide 329

Slide 329 text

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

Slide 330

Slide 330 text

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