Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Streams
Highland et compagnie
Guillaume Gautreau
Lead developer @ReportLinker
@ghusse
https://www.ghusse.com
Feedbacks
http://speakerscore.com/BX1L
Contact
@ghusse
guillaume@ghusse.com
Programme
● Pourquoi les streams
● Highland : API & caractéristiques
● Bonnes pratiques
En 2015
@mpjme
Youtube: funfunfunction
Je découvre FunFunFunction
Janvier 2016
Janvier 2016: vidéo sur les streams
Présentation de :
● highlandjs
● baconjs
● ReactiveX
Les streams
Ça a l’air sympa
Mais je ne vois pas trop
dans quels cas ça pourrait
nous être utile
Moi, Janvier 2016
1 an
plus tard
Utilisation chez ReportLinker
12
42
Projets
node
Projets dépendant
de highland
On a trouvé !
Qui utilise les
promesses ?
Et puis un jour...
Lancer un traitement sur
tous les enregistrements
d’une API paginée
Exemple
http://jsonplaceholder.typicode.com
/posts 100 items
/comments 500 items
/albums 100 items
/photos 5000 items
/tod...
Exemple
http://jsonplaceholder.typicode.com
/posts 100 items
/comments 500 items
/albums 100 items
/photos 5000 items
/tod...
const promiseLoad =
require('./paginationPromise');
promiseLoad()
.then(console.log);
const photos = require('./jsonPlaceholder').photos;
function loadFromPage(page, results = []){
return photos.list({ page }...
Code
https://github.com/ghusse/lyonjs-streams-code
Chargement avec promesses
1. Charge TOUT en mémoire
2. Attend 19s avant de pouvoir continuer
Et si on pouvait traiter
les résultats
au fil de l’eau ?
const promiseCallbackLoad =
require('./paginationPromiseWithCallbacks')
promiseCallbackLoad(
(error, result) => console.lo...
return photos.list({ page })
.then(response => {
response.results
.forEach(result => callback(undefined, result)));
if (pa...
return photos.list({ page })
.then(response => {
response.results
.forEach(result => callback(undefined, result)));
if (pa...
Promises
Callbacks
Welcome to callback hell, again
1. Gestion d’erreurs
2. Traitement asynchrone dans les callbacks
3. Regroupement des résul...
Promesses
+ Lisibilité du code
+ Chaînage des actions
+ Gestion d’erreur
− Un seul résultat
− Callback appelé une
fois à l...
Promesses + callbacks
+ Flexibilité
− Gestion d’erreur
− Lisibilité du code
− Chaînage des appels
Promesses
+
Callbacks
Promesses
+
Callbacks
Promesses
+
Streams
Promesses
+
Streams
Asynchronisme
Gestion d’erreur
Gestion du flux
Ressources
const streamLoad =
require("./paginationStream");
streamLoad()
.each(console.log)
.done();
const streamLoad =
require("./paginationStream");
streamLoad()
.each(console.log)
.done();
API
Exemple :
récupérer les URLs
{
"albumId": 1,
"id": 1,
"title": "accusamus beatae ad facilis cum
similique qui sunt",
"url": "http://placehold.it/600/92...
{
"albumId": 1,
"id": 1,
"title": "accusamus beatae ad facilis cum
similique qui sunt",
"url": "http://placehold.it/600/92...
const streamLoad =
require("./paginationStream");
streamLoad()
.map(photo => photo.url)
.each(console.log)
.done();
Exemple :
Uniquement les
photos avec un
titre de + de 4 mots
const streamLoad =
require("./paginationStream");
streamLoad()
.filter(
photo => photo.title.split(' ')
.length > 4
)
.map...
Quizz
Répondez au signal
Citez une 4ème
fonction sur les
streams
Méthodes sur les streams
each
map
filter
Méthodes sur les streams
each
map
filter
GO !
Méthodes sur les streams
each
map
filter
reduce
Méthodes sur les streams
each
map
filter
reduce
Programmation
fonctionnelle comme
sur les tableaux, mais
au fil de l’eau
Méthodes sur les streams
each
map
filter
reduce
Méthodes synchrones
Asynchronisme
Exemple
/posts 100 items
/comments 500 items
/albums 100 items
/photos 5000 items
/todos 200 items
/users 10 items
http://...
Exemple
/posts 100 items
/comments 500 items
/albums 100 items
/photos 5000 items
/todos 200 items
/users 10 items
http://...
const streamLoad = require("./paginationStream");
const { photos, albums } = require('./jsonPlaceholder');
streamLoad(albu...
flatmap
=
map asynchrone
flatmap
● Chaque élément du stream est mappé en un
nouveau stream
● Le contenu de chaque stream est envoyé dans le
stream
flatMap vs map
streamLoad(albums)
.flatMap(album =>
streamLoad(photos,
{ albumId: album.id }))
.each(console.log)
.done();...
flatFilter vs filter
Synchrone Asynchrone
.map .flatMap
.filter .flatFilter
flatFilter vs filter
Synchrone Asynchrone
.map .flatMap .map().sequence()
.filter .flatFilter
Promesses
+
Streams
FlatMap
.flatMap( )
Fonction qui doit renvoyer un
stream highland
Créer un stream Higland
const highland = require('highland');
const promise = Promise.resolve('value');
const stream = hig...
FlatMap
.flatMap(highland( ))
Fonction qui renvoie
une promesse
Créer un stream highland
● Array
● Iterator
● Iterable
● Promise
● Readable stream
● Events
● Function
Créer un stream highland
● Array
● Iterator
● Iterable
● Promise
● Readable stream
● Events
● Function
Traitements asynchr...
Créer un stream highland
● Array
● Iterator
● Iterable
● Promise
● Readable stream
● Events
● Function
Fichiers, requêtes ...
Créer un stream highland
● Array
● Iterator
● Iterable
● Promise
● Readable stream
● Events
● Function
Événements DOM (cli...
Créer un stream highland
● Array
● Iterator
● Iterable
● Promise
● Readable stream
● Events
● Function
Créer ses propres s...
back
pressure
Back-pressure
streamLoad(albums)
.tap(() => console.log(new Date(), "album"))
.flatMap(album =>
streamLoad(photos, { album...
Back-pressure
streamLoad(albums)
.tap(() => console.log(new Date(), "album"))
.flatMap(album =>
streamLoad(photos, { album...
Back-pressure
streamLoad(albums)
.tap(() => console.log(new Date(), "album"))
.flatMap(album =>
streamLoad(photos, { album...
Back-pressure
streamLoad(albums)
.tap(() => console.log(new Date(), "album"))
/*.flatMap(album =>
streamLoad(photos, { alb...
Back-pressure
Avec flatMap Sans flatMap
Back-Pressure
● Laziness
● S’adapte au plus lent
Back-pressure
Avec flatMap Sans flatMap
Back-Pressure
● Laziness
● S’adapte au plus lent
● Chargement différé (source)
Récap’
API
map/filter/reduce/tap
flatMap/flatFilter
ctor : promise, function
API
map/filter/reduce/tap
flatMap/flatFilter
ctor : promise, function
batch/sequence
errors/stopOnError
rateLimit
fork/mer...
http://highlandjs.org
3 bonnes
pratiques
Gérer les erreurs
Gérer les erreurs
source
.stopOnError(
error => {
// Do something
}
).done();
source
.errors(
(error, push) => {
// Do som...
Utiliser next dans
la création de
stream
Utiliser next
return highland((push, next) => {});
Pousser une valeur
dans le stream
Utiliser next
return highland((push, next) => {});
Pousser une valeur
dans le stream
Rediriger vers un
autre stream
Utiliser next
return highland((push, next) => {});
Pousser une valeur
dans le stream
Rediriger vers un
autre stream
back
p...
Streams =
où c’est nécessaire,
promesses =
partout ailleurs
const getThing = require('./getThing');
source
.flatMap(getThing)
.done();
Streams où c’est nécessaire
getThing doit
renvo...
Streams où c’est nécessaire
const getThing = require('./getThing');
source
.flatMap(v => highland(getThing(v)))
.done();
g...
Streams où c’est nécessaire
return new Promise((resolve, reject) => {
stream
.stopOnError(reject)
.collect().toArray(resol...
Feedbacks
http://speakerscore.com/BX1L
Contact
@ghusse
guillaume@ghusse.com
Streams avec HighlandJS
Streams avec HighlandJS
Upcoming SlideShare
Loading in …5
×

Streams avec HighlandJS

1,643 views

Published on

Présentation des streams haut-niveau en Javascript, avec HIghlandJS.

- Présentation des exemples où leur utilisation est intéressante
- API & utilisation avec les promesses
- Conseils et bonnes pratiques.

Published in: Technology
  • Be the first to comment

Streams avec HighlandJS

  1. 1. Streams Highland et compagnie
  2. 2. Guillaume Gautreau Lead developer @ReportLinker @ghusse https://www.ghusse.com
  3. 3. Feedbacks http://speakerscore.com/BX1L Contact @ghusse guillaume@ghusse.com
  4. 4. Programme ● Pourquoi les streams ● Highland : API & caractéristiques ● Bonnes pratiques
  5. 5. En 2015
  6. 6. @mpjme Youtube: funfunfunction Je découvre FunFunFunction
  7. 7. Janvier 2016
  8. 8. Janvier 2016: vidéo sur les streams Présentation de : ● highlandjs ● baconjs ● ReactiveX
  9. 9. Les streams Ça a l’air sympa
  10. 10. Mais je ne vois pas trop dans quels cas ça pourrait nous être utile Moi, Janvier 2016
  11. 11. 1 an plus tard
  12. 12. Utilisation chez ReportLinker 12 42 Projets node Projets dépendant de highland
  13. 13. On a trouvé !
  14. 14. Qui utilise les promesses ?
  15. 15. Et puis un jour...
  16. 16. Lancer un traitement sur tous les enregistrements d’une API paginée
  17. 17. Exemple http://jsonplaceholder.typicode.com /posts 100 items /comments 500 items /albums 100 items /photos 5000 items /todos 200 items /users 10 items
  18. 18. Exemple http://jsonplaceholder.typicode.com /posts 100 items /comments 500 items /albums 100 items /photos 5000 items /todos 200 items /users 10 items
  19. 19. const promiseLoad = require('./paginationPromise'); promiseLoad() .then(console.log);
  20. 20. const photos = require('./jsonPlaceholder').photos; function loadFromPage(page, results = []){ return photos.list({ page }) .then(response => { const nextResults = results.concat(response.results); if (page >= response.pages){ return results; } return loadFromPage(page + 1, nextResults); }); }
  21. 21. Code https://github.com/ghusse/lyonjs-streams-code
  22. 22. Chargement avec promesses 1. Charge TOUT en mémoire 2. Attend 19s avant de pouvoir continuer
  23. 23. Et si on pouvait traiter les résultats au fil de l’eau ?
  24. 24. const promiseCallbackLoad = require('./paginationPromiseWithCallbacks') promiseCallbackLoad( (error, result) => console.log(result) ).then(() => console.log('done'));
  25. 25. return photos.list({ page }) .then(response => { response.results .forEach(result => callback(undefined, result))); if (page >= response.pages){ return; } return loadFromPage(page + 1, callback); }) .catch(error => callback(error));
  26. 26. return photos.list({ page }) .then(response => { response.results .forEach(result => callback(undefined, result))); if (page >= response.pages){ return; } return loadFromPage(page + 1, callback); }) .catch(error => callback(error));
  27. 27. Promises Callbacks
  28. 28. Welcome to callback hell, again 1. Gestion d’erreurs 2. Traitement asynchrone dans les callbacks 3. Regroupement des résultats 4. Ressources (mémoire, flood réseau etc)
  29. 29. Promesses + Lisibilité du code + Chaînage des actions + Gestion d’erreur − Un seul résultat − Callback appelé une fois à la fin
  30. 30. Promesses + callbacks + Flexibilité − Gestion d’erreur − Lisibilité du code − Chaînage des appels
  31. 31. Promesses + Callbacks
  32. 32. Promesses + Callbacks
  33. 33. Promesses + Streams
  34. 34. Promesses + Streams Asynchronisme Gestion d’erreur Gestion du flux Ressources
  35. 35. const streamLoad = require("./paginationStream"); streamLoad() .each(console.log) .done();
  36. 36. const streamLoad = require("./paginationStream"); streamLoad() .each(console.log) .done();
  37. 37. API
  38. 38. Exemple : récupérer les URLs
  39. 39. { "albumId": 1, "id": 1, "title": "accusamus beatae ad facilis cum similique qui sunt", "url": "http://placehold.it/600/92c952", "thumbnailUrl": "http://placehold.it/150/30ac17" }
  40. 40. { "albumId": 1, "id": 1, "title": "accusamus beatae ad facilis cum similique qui sunt", "url": "http://placehold.it/600/92c952", "thumbnailUrl": "http://placehold.it/150/30ac17" }
  41. 41. const streamLoad = require("./paginationStream"); streamLoad() .map(photo => photo.url) .each(console.log) .done();
  42. 42. Exemple : Uniquement les photos avec un titre de + de 4 mots
  43. 43. const streamLoad = require("./paginationStream"); streamLoad() .filter( photo => photo.title.split(' ') .length > 4 ) .map(photo => photo.url) .each(console.log) .done()
  44. 44. Quizz Répondez au signal
  45. 45. Citez une 4ème fonction sur les streams
  46. 46. Méthodes sur les streams each map filter
  47. 47. Méthodes sur les streams each map filter GO !
  48. 48. Méthodes sur les streams each map filter reduce
  49. 49. Méthodes sur les streams each map filter reduce Programmation fonctionnelle comme sur les tableaux, mais au fil de l’eau
  50. 50. Méthodes sur les streams each map filter reduce Méthodes synchrones
  51. 51. Asynchronisme
  52. 52. Exemple /posts 100 items /comments 500 items /albums 100 items /photos 5000 items /todos 200 items /users 10 items http://jsonplaceholder.typicode.com 1. Lister les albums 2. Récupérer la liste des photos de chaque album
  53. 53. Exemple /posts 100 items /comments 500 items /albums 100 items /photos 5000 items /todos 200 items /users 10 items http://jsonplaceholder.typicode.com 1. Lister les albums 2. Récupérer la liste des photos de chaque album PS : tout est paginé
  54. 54. const streamLoad = require("./paginationStream"); const { photos, albums } = require('./jsonPlaceholder'); streamLoad(albums) .flatMap(album => streamLoad(photos, { albumId: album.id })) .filter(photo => photo.title.split(' ').length > 4) .map(photo => photo.url) .each(console.log) .done();
  55. 55. flatmap = map asynchrone
  56. 56. flatmap ● Chaque élément du stream est mappé en un nouveau stream ● Le contenu de chaque stream est envoyé dans le stream
  57. 57. flatMap vs map streamLoad(albums) .flatMap(album => streamLoad(photos, { albumId: album.id })) .each(console.log) .done(); streamLoad(albums) .map(album => streamLoad(photos, { albumId: album.id })) .each(console.log) .done(); // Une ligne de log par PHOTO { albumId: 1, id: 1, ... { albumId: 1, id: 2, ... // Une ligne par ALBUM Stream { domain: null, ...
  58. 58. flatFilter vs filter Synchrone Asynchrone .map .flatMap .filter .flatFilter
  59. 59. flatFilter vs filter Synchrone Asynchrone .map .flatMap .map().sequence() .filter .flatFilter
  60. 60. Promesses + Streams
  61. 61. FlatMap .flatMap( ) Fonction qui doit renvoyer un stream highland
  62. 62. Créer un stream Higland const highland = require('highland'); const promise = Promise.resolve('value'); const stream = highland(promise);
  63. 63. FlatMap .flatMap(highland( )) Fonction qui renvoie une promesse
  64. 64. Créer un stream highland ● Array ● Iterator ● Iterable ● Promise ● Readable stream ● Events ● Function
  65. 65. Créer un stream highland ● Array ● Iterator ● Iterable ● Promise ● Readable stream ● Events ● Function Traitements asynchrones
  66. 66. Créer un stream highland ● Array ● Iterator ● Iterable ● Promise ● Readable stream ● Events ● Function Fichiers, requêtes HTTP
  67. 67. Créer un stream highland ● Array ● Iterator ● Iterable ● Promise ● Readable stream ● Events ● Function Événements DOM (client)
  68. 68. Créer un stream highland ● Array ● Iterator ● Iterable ● Promise ● Readable stream ● Events ● Function Créer ses propres streams
  69. 69. back pressure
  70. 70. Back-pressure streamLoad(albums) .tap(() => console.log(new Date(), "album")) .flatMap(album => streamLoad(photos, { albumId: album.id })) .each(photo => { /*NOOP*/ });
  71. 71. Back-pressure streamLoad(albums) .tap(() => console.log(new Date(), "album")) .flatMap(album => streamLoad(photos, { albumId: album.id })) .each(photo => { /*NOOP*/ });
  72. 72. Back-pressure streamLoad(albums) .tap(() => console.log(new Date(), "album")) .flatMap(album => streamLoad(photos, { albumId: album.id })) .each(photo => { /*NOOP*/ }); Code 1 avec flatMap
  73. 73. Back-pressure streamLoad(albums) .tap(() => console.log(new Date(), "album")) /*.flatMap(album => streamLoad(photos, { albumId: album.id }))*/ .each(album => { /*NOOP*/ }); Code 2 sans flatMap
  74. 74. Back-pressure Avec flatMap Sans flatMap
  75. 75. Back-Pressure ● Laziness ● S’adapte au plus lent
  76. 76. Back-pressure Avec flatMap Sans flatMap
  77. 77. Back-Pressure ● Laziness ● S’adapte au plus lent ● Chargement différé (source)
  78. 78. Récap’
  79. 79. API map/filter/reduce/tap flatMap/flatFilter ctor : promise, function
  80. 80. API map/filter/reduce/tap flatMap/flatFilter ctor : promise, function batch/sequence errors/stopOnError rateLimit fork/merge pipe
  81. 81. http://highlandjs.org
  82. 82. 3 bonnes pratiques
  83. 83. Gérer les erreurs
  84. 84. Gérer les erreurs source .stopOnError( error => { // Do something } ).done(); source .errors( (error, push) => { // Do something } ).done();
  85. 85. Utiliser next dans la création de stream
  86. 86. Utiliser next return highland((push, next) => {}); Pousser une valeur dans le stream
  87. 87. Utiliser next return highland((push, next) => {}); Pousser une valeur dans le stream Rediriger vers un autre stream
  88. 88. Utiliser next return highland((push, next) => {}); Pousser une valeur dans le stream Rediriger vers un autre stream back pressure
  89. 89. Streams = où c’est nécessaire, promesses = partout ailleurs
  90. 90. const getThing = require('./getThing'); source .flatMap(getThing) .done(); Streams où c’est nécessaire getThing doit renvoyer un stream
  91. 91. Streams où c’est nécessaire const getThing = require('./getThing'); source .flatMap(v => highland(getThing(v))) .done(); getThing renvoie une promesse Streams limités à ce traitement
  92. 92. Streams où c’est nécessaire return new Promise((resolve, reject) => { stream .stopOnError(reject) .collect().toArray(resolve); });
  93. 93. Feedbacks http://speakerscore.com/BX1L Contact @ghusse guillaume@ghusse.com

×