à la découverte des observables - humantalks paris 2017

47
@nicoespeon À la découverte des Observables Meetup HumanTalks Paris Décembre 2017 1

Upload: nicolas-carlo

Post on 17-Mar-2018

37 views

Category:

Technology


8 download

TRANSCRIPT

Page 1: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

À la découverte des Observables

Meetup HumanTalks Paris Décembre 2017

1

Page 2: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 2

Page 3: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 3

Page 4: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 4

Back-end

1

23

Page 5: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 5

$search.on('click', () !=> { fetchTrips() .then(({data}) !=> renderFoundTrips(data))

.catch(handleError) })

Page 6: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 6

Page 7: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 7

Back-end

1

3

2

4

Si c’est incomplet, on « poll »

Page 8: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 8

$search.on('click', () !=> { fetchTrips() .then(renderFoundTripsAndPoll) .catch(handleError) })

function renderFoundTripsAndPoll({data, isComplete}) { renderFoundTrips(data) if (!isComplete) { pollTrips() .then(renderFoundTripsAndPoll) .catch(handleError) } }

Page 9: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 9

Page 10: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 10

Back-end

1

3

2

4

On optimise le polling

5s

Page 11: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 11

$search.on('click', () !=> { fetchTrips() .then(renderFoundTripsAndPoll) .catch(handleError) })

function renderFoundTripsAndPoll({data, isComplete}) { const DELAY_BEFORE_POLLING_IN_MS = 5000

renderFoundTrips(data) if (!isComplete) { setTimeout(() !=> { pollTrips() .then(renderFoundTripsAndPoll) .catch(handleError) }, DELAY_BEFORE_POLLING_IN_MS ) } }

Page 12: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

« Et si on lançait la recherche au fur et à

mesure de la saisie ? »

12

Page 13: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 13

const DEBOUNCE_TIME_IN_MS = 250 let fetchTripsTimeout

$input.on('keypress', () !=> { clear(fetchTripsTimeout) fetchTripsTimeout = setTimeout(() !=> { fetchTrips() .then(renderFoundTripsAndPoll) .catch(handleError) }, DEBOUNCE_TIME_IN_MS); })

function renderFoundTripsAndPoll({data, isComplete}) { const DELAY_BEFORE_POLLING_IN_MS = 5000 renderFoundTrips(data) if (!isComplete) { setTimeout(() !=> { pollTrips() .then(renderFoundTripsAndPoll) .catch(handleError) }, DELAY_BEFORE_POLLING_IN_MS ) } }

Page 14: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 14

const DEBOUNCE_TIME_IN_MS = 250 let fetchTripsTimeout

$input.on('keypress', () !=> { clear(fetchTripsTimeout) fetchTripsTimeout = setTimeout(() !=> { fetchTrips() .then(renderFoundTripsAndPoll) .catch(handleError) }, DEBOUNCE_TIME_IN_MS); })

function renderFoundTripsAndPoll({data, isComplete}) { const DELAY_BEFORE_POLLING_IN_MS = 5000 renderFoundTrips(data) if (!isComplete) { setTimeout(() !=> { pollTrips() .then(renderFoundTripsAndPoll) .catch(handleError) }, DELAY_BEFORE_POLLING_IN_MS ) } }

Page 15: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 15

Back-end

1

2

3

Nous avons un bug…

4

Oups

Page 16: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 16

Page 17: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Nicolas Carlo

17

Page 18: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Servez-vous des Observables pour gérer des scénarios asynchrones compliqués

18

Page 19: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Si on modélisait ça autrement ?

19

Un événement

Une erreur

Flux terminé

temps

= Observable

Page 20: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

- Andre Staltz, 2 minute introduction to Rx

« Think of it as an asynchronous

immutable array »

20

Page 21: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Utilisez les Observables avec ReactiveX

• Projet porté par Microsoft, en open-source depuis 2012

• Implémente les Observables dans de nombreux langages (Java, Python, JS, .NET, Go, Ruby, Elixir, Swift…)

• Fournit une API pour manipuler des flux observables

21

Page 22: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Réfléchissez avec des diagrammes Marbles

22

http://rxmarbles.com/

Page 23: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 23

Page 24: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

clickStream ➜ click$

24

Page 25: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Fetch au click

25

flatMap

click$

fetchedTrips$

Page 26: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 26

const fetchedTrips$ = fromEvent($search, 'click') .flatMap(fetchTrips)

fetchedTrips$.subscribe( ({data}) !=> renderFoundTrips(data), handleError )

Page 27: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Le polling

27

flatMap

isRequestComplete$

polledTrips$

filter

Page 28: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 28

const isRequestComplete$ = new Subject()

const fetchedTrips$ = fromEvent($search, 'click') .flatMap(fetchTrips)

const polledTrips$ = isRequestComplete$ .filter((isComplete) !=> !isComplete) .flatMap(pollTrips)

const foundTrips$ = merge(fetchedTrips$, polledTrips$)

foundTrips$.subscribe( ({data, isComplete}) !=> { renderFoundTrips(data) isRequestComplete$.next(isComplete) }, handleError )

Page 29: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Le polling optimisé

29

flatMap

isRequestComplete$

polledTrips$

delay

Page 30: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 30

const isRequestComplete$ = new Subject()

const fetchedTrips$ = fromEvent($search, 'click') .flatMap(fetchTrips)

const DELAY_BEFORE_POLLING_IN_MS = 5000 const polledTrips$ = isRequestComplete$ .filter((isComplete) !=> !isComplete) .delay(DELAY_BEFORE_POLLING_IN_MS ) .flatMap(pollTrips)

const foundTrips$ = merge(fetchedTrips$, polledTrips$)

foundTrips$.subscribe( ({data, isComplete}) !=> { renderFoundTrips(data) isRequestComplete$.next(isComplete) }, handleError )

Page 31: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

« Et si on lançait la recherche au fur et à

mesure de la saisie ? »

31

Page 32: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Fetch au fur et à mesure

32

flatMap

keypress$

fetchedTrips$

debounce

Page 33: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 33

const isRequestComplete$ = new Subject()

const DEBOUNCE_TIME_IN_MS = 250 const fetchedTrips$ = fromEvent($input, 'keypress') .debounce(DEBOUNCE_TIME_IN_MS) .flatMap(fetchTrips)

const DELAY_BEFORE_POLLING_IN_MS = 5000 const polledTrips$ = isRequestComplete$ .filter((isComplete) !=> !isComplete) .delay(DELAY_BEFORE_POLLING_IN_MS ) .flatMap(pollTrips)

const foundTrips$ = merge(fetchedTrips$, polledTrips$)

foundTrips$.subscribe( ({data, isComplete}) !=> { renderFoundTrips(data) isRequestComplete$.next(isComplete) }, handleError )

Page 34: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 34

Page 35: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

FlatMapLatest

35

reactivex.io/documentation/operators/flatmap.html

Page 36: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 36

const isRequestComplete$ = new Subject()

const DEBOUNCE_TIME_IN_MS = 250 const fetchedTrips$ = fromEvent($input, 'keypress') .debounce(DEBOUNCE_TIME_IN_MS) .flatMapLatest(fetchTrips)

const DELAY_BEFORE_POLLING_IN_MS = 5000 const polledTrips$ = isRequestComplete$ .filter((isComplete) !=> !isComplete) .delay(DELAY_BEFORE_POLLING_IN_MS ) .flatMapLatest(pollTrips)

const foundTrips$ = merge(fetchedTrips$, polledTrips$)

foundTrips$.subscribe( ({data, isComplete}) !=> { renderFoundTrips(data) isRequestComplete$.next(isComplete) }, handleError )

Page 37: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 37

const isRequestComplete$ = new Subject()

const DEBOUNCE_TIME_IN_MS = 250 const fetchedTrips$ = fromEvent($input, 'keypress') .debounce(DEBOUNCE_TIME_IN_MS) .flatMapLatest(fetchTrips)

const DELAY_BEFORE_POLLING_IN_MS = 5000 const polledTrips$ = isRequestComplete$ .filter((isComplete) !=> !isComplete) .delay(DELAY_BEFORE_POLLING_IN_MS ) .flatMapLatest(pollTrips)

const foundTrips$ = merge(fetchedTrips$, polledTrips$)

foundTrips$.subscribe( ({data, isComplete}) !=> { renderFoundTrips(data) isRequestComplete$.next(isComplete) }, handleError )

Page 38: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Qu’avons-nous gagné ?

✓ Code déclaratif, facile à faire évoluer

✓ Logique applicative sans effets de bords, facile à tester

✓ Observables composables, facile à ré-utiliser

38

Page 39: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

L’usage des Observables se popularise dans le web

• Embarqué par défaut dans Angular

• Il y a des adaptations pour chaque librairie : redux−observable, vue-rx…

• Cycle.js est un framework fonctionnel et réactif, basé sur l’usage des Observables

39

Page 40: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Pensez aux Observables pour résoudre vos

problèmes asynchrones non triviaux

40

Page 41: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 41

Bienvenue sur la route de la programmation réactive !

Page 43: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Des diagrammes Marbles dans le code

43

const polledTrips$ = isRequestComplete$ !// !!---(true)----(false)----------(false)-------> .filter((isComplete) !=> !isComplete) !// ------------(false)----------(false)--------> .delay(DELAY_BEFORE_POLLING_IN_MS ) !// ----------------(false)----------(false)----> .flatMapLatest(pollTrips) !// ----------------(A)--------------(A)-------->

Page 44: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon

Analysons les strates du code

44

Gestion du temps (debounce, délai)

Logique applicative

Effets de bord (rendu, gestion des erreurs)

Évènements du DOM (click, keypress)

Page 45: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 45

const DEBOUNCE_TIME_IN_MS = 250 let fetchTripsTimeout

$input.on('keypress', () !=> { clear(fetchTripsTimeout) fetchTripsTimeout = setTimeout(() !=> { fetchTrips() .then(renderFoundTripsAndPoll) .catch(handleError) }, DEBOUNCE_TIME_IN_MS); })

function renderFoundTripsAndPoll({data, isComplete}) { const DELAY_BEFORE_POLLING_IN_MS = 5000 renderFoundTrips(data) if (!isComplete) { setTimeout(() !=> { pollTrips() .then(renderFoundTripsAndPoll) .catch(handleError) }, DELAY_BEFORE_POLLING_IN_MS ) } }

Page 46: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 46

const isRequestComplete$ = new Subject()

const DEBOUNCE_TIME_IN_MS = 250 const fetchedTrips$ = fromEvent($input, 'keypress') .debounce(DEBOUNCE_TIME_IN_MS) .flatMapLatest(fetchTrips)

const DELAY_BEFORE_POLLING_IN_MS = 5000 const polledTrips$ = isRequestComplete$ .filter((isComplete) !=> !isComplete) .delay(DELAY_BEFORE_POLLING_IN_MS ) .flatMapLatest(pollTrips)

const foundTrips$ = merge(fetchedTrips$, polledTrips$)

foundTrips$.subscribe( ({data, isComplete}) !=> { renderFoundTrips(data) isRequestComplete$.next(isComplete) }, handleError )

Page 47: À la découverte des Observables - HumanTalks Paris 2017

@nicoespeon 47

14 alternances

Effets de bords couplés à la logique applicative

6 alternances

Effets de bords isolés