5. La découverte du JS
Interprété
Dynamique
Single-threaded
"Functions are first-
class citizen"
6. La découverte du JS
Interprété
Dynamique
Single-threaded
"Functions are first-
class citizen"
Orienté Objet ?
7. Les choses changent
Coté serveur
Large communauté
Production ready
La quête du Full stack
8. Les choses changent
Coté serveur
Large communauté
Production ready
La quête du Full stack
Un langage en évolution
En 2015, EcmaScript 6
Multi-paradigme
Un langage expressif
9. Pilot : notre fil rouge
Ordonnanceur en NodeJS
Déclenche et suit l’exécution de tâches
10. Pilot : notre fil rouge
Ordonnanceur en NodeJS
Déclenche et suit l’exécution de tâches
Task <<abstract>>
name: String
start: Number
end: Number
next: Task
run: (param: Object, done: Function)
_execute: (param: Object, done: Function)
Parallel
tasks: [Task]
field: String
11. Pilot : notre fil rouge
Ordonnanceur en NodeJS
Déclenche et suit l’exécution de tâches
Task <<abstract>>
name: String
start: Number
end: Number
next: Task
run: (param: Object, done: Function)
_execute: (param: Object, done: Function)
Parallel
tasks: [Task]
field: String
Sorter
_execute()
Crawler
page: Number
_execute()
13. Déclarer une classe
Un seul constructeur class Task {
constructor(name, next) {}
toString() {}
static display(step) {}
get duration() {}
// new Task('t1').duration
}
14. Déclarer une classe
Un seul constructeur
Des méthodes
class Task {
constructor(name, next) {}
toString() {}
static display(step) {}
get duration() {}
// new Task('t1').duration
}
15. Déclarer une classe
Un seul constructeur
Des méthodes
Méthode de classe
class Task {
constructor(name, next) {}
toString() {}
static display(step) {}
get duration() {}
// new Task('t1').duration
}
16. Déclarer une classe
Un seul constructeur
Des méthodes
Méthode de classe
Des getter/setters
class Task {
constructor(name, next) {}
toString() {}
static display(step) {}
get duration() {}
// new Task('t1').duration
}
17. Déclarer une classe
Un seul constructeur
Des méthodes
Méthode de classe
Des getter/setters
Pas d’attributs : initialisés dans le constructeur
Tout est public
class Task {
constructor(name, next) {}
toString() {}
static display(step) {}
get duration() {}
// new Task('t1').duration
}
18. Interpolation (template string)
Utilisation de variable à l’intérieur des chaînes
toString() {
let className = this.constructor.name;
return `${className} ${this.name}`.trim();
}
19. Interpolation (template string)
Utilisation de variable à l’intérieur des chaînes
Délimité par l’accent grave (backquote)
toString() {
let className = this.constructor.name;
return `${className} ${this.name}`.trim();
}
20. Interpolation (template string)
Utilisation de variable à l’intérieur des chaînes
Délimité par l’accent grave (backquote)
Des placeholders contenant une expression
toString() {
let className = this.constructor.name;
return `${className} ${this.name}`.trim();
}
static display(task) {
return task.next ?
`${task.toString()} > ${Task.display(task.next)}`:
task.toString();
}
21. Interpolation (template string)
Utilisation de variable à l’intérieur des chaînes
Délimité par l’accent grave (backquote)
Des placeholders contenant une expression
Conserve les caractères blancs
toString() {
let className = this.constructor.name;
return `${className} ${this.name}`.trim();
}
static display(task) {
return task.next ?
`${task.toString()} > ${Task.display(task.next)}`:
task.toString();
}
22. Portée des variables (block scoping)
Porté d’une variable ES5 ?
let className = this.constructor.name;
function sayHi(name) {
if (name) {
var txt = 'Hi ';
}
return txt + name;
}
23. Portée des variables (block scoping)
Porté d’une variable ES5 ?
La fonction :
sayHi('Tom') === 'Hi Tom'
sayHi() === NaN
let className = this.constructor.name;
function sayHi(name) {
if (name) {
var txt = 'Hi ';
}
return txt + name;
}
24. Portée des variables (block scoping)
Porté d’une variable ES5 ?
La fonction :
sayHi('Tom') === 'Hi Tom'
sayHi() === NaN
Avec let, portée du bloc
sayHi('Tom') >> ReferenceError
Et même des constantes
let className = this.constructor.name;
function sayHi(name) {
if (name) {
var txt = 'Hi ';
}
return txt + name;
}
const maxQuotes = 99;
let
26. Modules
ES5 n’a pas de mécanisme de modularisation
Fichier task.js
Fichier parallel.js
D’autres syntaxes seront vues par la suite
import {Task} from './task';
export class Parallel extends Task {
// ...
}
export class Task {
// ...
}
32. Paramètres par défaut et "literal object"
On peut initialiser les
paramètres
constructor(name, next=null) {
Object.assign(this, {
name,
next,
end: null,
start: null,
success: null
});
}
33. Paramètres par défaut et "literal object"
On peut initialiser les
paramètres
Nouvelle fonction
constructor(name, next=null) {
Object.assign(this, {
name,
next,
end: null,
start: null,
success: null
});
}
34. Paramètres par défaut et "literal object"
On peut initialiser les
paramètres
Nouvelle fonction
Objet littéral ES6
Notation raccourcie
constructor(name, next=null) {
Object.assign(this, {
name,
next,
end: null,
start: null,
success: null
});
}
35. Paramètres par défaut et "literal object"
On peut initialiser les
paramètres
Nouvelle fonction
Objet littéral ES6
Notation raccourcie
constructor(name, next=null) {
Object.assign(this, {
name,
next,
end: null,
start: null,
success: null
});
}
: name,
: next,
36. get duration() {}
toString() {}
Paramètres par défaut et "literal object"
On peut initialiser les
paramètres
Nouvelle fonction
Objet littéral ES6
Notation raccourcie
Aussi utilisé dans les
classes
constructor(name, next=null) {
Object.assign(this, {
name,
next,
end: null,
start: null,
success: null
});
}
37. get duration() {}
toString() {}
Paramètres par défaut et "literal object"
On peut initialiser les
paramètres
Nouvelle fonction
Objet littéral ES6
Notation raccourcie
Aussi utilisé dans les
classes
Getter/setter
constructor(name, next=null) {
Object.assign(this, {
name,
next,
end: null,
start: null,
success: null
});
}
38. get duration() {}
toString() {}
Object.defineProperty(this, 'duration', {
get : function() {},
enumerable : true
});
Paramètres par défaut et "literal object"
On peut initialiser les
paramètres
Nouvelle fonction
Objet littéral ES6
Notation raccourcie
Aussi utilisé dans les
classes
Getter/setter
constructor(name, next=null) {
Object.assign(this, {
name,
next,
end: null,
start: null,
success: null
});
}
39. get duration() {}
toString() {}
Paramètres par défaut et "literal object"
On peut initialiser les
paramètres
Nouvelle fonction
Objet littéral ES6
Notation raccourcie
Aussi utilisé dans les
classes
Getter/setter
Méthodes raccourcies
constructor(name, next=null) {
Object.assign(this, {
name,
next,
end: null,
start: null,
success: null
});
}
40. get duration() {}
toString() {}
Paramètres par défaut et "literal object"
On peut initialiser les
paramètres
Nouvelle fonction
Objet littéral ES6
Notation raccourcie
Aussi utilisé dans les
classes
Getter/setter
Méthodes raccourcies
constructor(name, next=null) {
Object.assign(this, {
name,
next,
end: null,
start: null,
success: null
});
}
: function() {}
41. get duration() {}
toString() {}
Paramètres par défaut et "literal object"
On peut initialiser les
paramètres
Nouvelle fonction
Objet littéral ES6
Notation raccourcie
Aussi utilisé dans les
classes
Getter/setter
Méthodes raccourcies
constructor(name, next=null) {
Object.assign(this, {
name,
next,
end: null,
start: null,
success: null
});
}
42. "Rest operator" & "Arrow function"
Tous les arguments non
déclarés dans un tableau
run(...args) {
let done = args.pop();
let params = args.pop()||{};
this.start = Date.now();
this._execute(params,
(err, results) => {
this.success = err == null;
this.end = Date.now();
if (err || !this.next) {
done(err, results);
} else {
this.next.run(params, done);
}
});
}
43. "Rest operator" & "Arrow function"
Tous les arguments non
déclarés dans un tableau
Fonction fléchée :
run(...args) {
let done = args.pop();
let params = args.pop()||{};
this.start = Date.now();
this._execute(params,
(err, results) => {
this.success = err == null;
this.end = Date.now();
if (err || !this.next) {
done(err, results);
} else {
this.next.run(params, done);
}
});
}
44. "Rest operator" & "Arrow function"
Tous les arguments non
déclarés dans un tableau
Fonction fléchée :
Conserve le this
run(...args) {
let done = args.pop();
let params = args.pop()||{};
this.start = Date.now();
this._execute(params,
(err, results) => {
this.success = err == null;
this.end = Date.now();
if (err || !this.next) {
done(err, results);
} else {
this.next.run(params, done);
}
});
}
45. "Rest operator" & "Arrow function"
Tous les arguments non
déclarés dans un tableau
Fonction fléchée :
Conserve le this
Notation raccourcie
toString() {
let sub = this.tasks.map(t =>
`(${Parallel.display(t)})`
).join(' | ');
46. "Rest operator" & "Arrow function"
Tous les arguments non
déclarés dans un tableau
Fonction fléchée :
Conserve le this
Notation raccourcie
1 paramètre
parenthèses optionnelles
toString() {
let sub = this.tasks.map(t =>
`(${Parallel.display(t)})`
).join(' | ');
47. "Rest operator" & "Arrow function"
Tous les arguments non
déclarés dans un tableau
Fonction fléchée :
Conserve le this
Notation raccourcie
1 paramètre
parenthèses optionnelles
1 expression
bloc optionnel +
return implicite
toString() {
let sub = this.tasks.map(t =>
`(${Parallel.display(t)})`
).join(' | ');
48. "For of", parcours de collections
Parcours des
éléments d’un
iterable
_execute(params, done) {
let results = [];
let finished = 0;
for (let task of this.tasks) {
task.run(params, (err, data) => {
if (data && data[this.field]) {
results = results.concat(
data[this.field]);
}
finished++;
if (finished === this.tasks.length) {
done(null, {
[this.field]: results
});
}
});
}}
49. "For of", parcours de collections
Parcours des
éléments d’un
iterable
Array, Set, Map
Pas d’index
Interruptible
_execute(params, done) {
let results = [];
let finished = 0;
for (let task of this.tasks) {
task.run(params, (err, data) => {
if (data && data[this.field]) {
results = results.concat(
data[this.field]);
}
finished++;
if (finished === this.tasks.length) {
done(null, {
[this.field]: results
});
}
});
}}
50. "For of", parcours de collections
Parcours des
éléments d’un
iterable
Array, Set, Map
Pas d’index
Interruptible
Objet littéral :
champ
dynamique
_execute(params, done) {
let results = [];
let finished = 0;
for (let task of this.tasks) {
task.run(params, (err, data) => {
if (data && data[this.field]) {
results = results.concat(
data[this.field]);
}
finished++;
if (finished === this.tasks.length) {
done(null, {
[this.field]: results
});
}
});
}}
51. "For of", parcours de collections
Parcours des
éléments d’un
iterable
Array, Set, Map
Pas d’index
Interruptible
Objet littéral :
champ
dynamique
_execute(params, done) {
let results = [];
let finished = 0;
for (let task of this.tasks) {
task.run(params, (err, data) => {
if (data && data[this.field]) {
results = results.concat(
data[this.field]);
}
finished++;
if (finished === this.tasks.length) {
done(null, {
[this.field]: results
});
}
});
}}
53. Modules (2)
Import sélectif de N symboles
import {Parallel} from '../parallel';
import {Task as BaseTask} from '../task';
import nbQuotes, * as utils from './utils';
54. Modules (2)
Import sélectif de N symboles
Import avec alias
import {Parallel} from '../parallel';
import {Task as BaseTask} from '../task';
import nbQuotes, * as utils from './utils';
55. Modules (2)
Import sélectif de N symboles
Import avec alias
Import du symbole par défaut
import {Parallel} from '../parallel';
import {Task as BaseTask} from '../task';
import nbQuotes, * as utils from './utils';
56. Modules (2)
Import sélectif de N symboles
Import avec alias
Import du symbole par défaut
const maxQuotes = 99;
export default maxQuotes;
import {Parallel} from '../parallel';
import {Task as BaseTask} from '../task';
import nbQuotes, * as utils from './utils';
57. Modules (2)
Import sélectif de N symboles
Import avec alias
Import du symbole par défaut
Import de tous les symboles dans une
variable conteneur
const maxQuotes = 99;
export default maxQuotes;
import {Parallel} from '../parallel';
import {Task as BaseTask} from '../task';
import nbQuotes, * as utils from './utils';
61. "Spread operator" & déstructuration
"Rest operator"
paramètres après
options
"Spread operator"
Eclate un tableau à
l’appel d’une fonction
class Crawler extends Task {
constructor(options, ...args) {
let {page} = options;
args.unshift(`page ${page}`);
super(...args);
Object.assign(this, options);
}
62. "Spread operator" & déstructuration
"Rest operator"
paramètres après
options
"Spread operator"
Eclate un tableau à
l’appel d’une fonction
class Crawler extends Task {
constructor(options, ...args) {
let {page} = options;
args.unshift(`page ${page}`);
super(...args);
Object.assign(this, options);
}
super.apply(this, args)
63. Déstructuration
"Spread operator" & déstructuration
"Rest operator"
paramètres après
options
"Spread operator"
Eclate un tableau à
l’appel d’une fonction
Déstructuration
class Crawler extends Task {
constructor(options, ...args) {
let {page} = options;
args.unshift(`page ${page}`);
super(...args);
Object.assign(this, options);
}
64. Déstructuration
"Spread operator" & déstructuration
"Rest operator"
paramètres après
options
"Spread operator"
Eclate un tableau à
l’appel d’une fonction
Déstructuration
Extrait de l’objet option l’attribut page dans une variable de
même nom
class Crawler extends Task {
constructor(options, ...args) {
let {page} = options;
args.unshift(`page ${page}`);
super(...args);
Object.assign(this, options);
}
65. Déstructuration
"Spread operator" & déstructuration
"Rest operator"
paramètres après
options
"Spread operator"
Eclate un tableau à
l’appel d’une fonction
Déstructuration
Extrait de l’objet option l’attribut page dans une variable de
même nom
Sur les tableaux, les objets
Imbrication, alias
class Crawler extends Task {
constructor(options, ...args) {
let {page} = options;
args.unshift(`page ${page}`);
super(...args);
Object.assign(this, options);
}
66. export default function main() {
let sorter = new Sorter();
const nbWorkers = 100;
let crawlers = Array.from(new Array(nbWorkers), (x, i) =>
new Crawler({page: i+1}, sorter)
);
new Parallel({tasks: crawlers, field: 'data'}, sorter).run(
(err, results) => {
let {data: [{fact, points: score}]=[]} = results;
console.log(`best fact found (${score} pts) :
${fact}`);
});
}
Pour finir…
Export
par défaut
67. export default function main() {
let sorter = new Sorter();
const nbWorkers = 100;
let crawlers = Array.from(new Array(nbWorkers), (x, i) =>
new Crawler({page: i+1}, sorter)
);
new Parallel({tasks: crawlers, field: 'data'}, sorter).run(
(err, results) => {
let {data: [{fact, points: score}]=[]} = results;
console.log(`best fact found (${score} pts) :
${fact}`);
});
}
Pour finir…
Export
par défaut
Portée
bloc
68. export default function main() {
let sorter = new Sorter();
const nbWorkers = 100;
let crawlers = Array.from(new Array(nbWorkers), (x, i) =>
new Crawler({page: i+1}, sorter)
);
new Parallel({tasks: crawlers, field: 'data'}, sorter).run(
(err, results) => {
let {data: [{fact, points: score}]=[]} = results;
console.log(`best fact found (${score} pts) :
${fact}`);
});
}
Pour finir…
Export
par défaut
Portée
bloc
API
étendue
69. export default function main() {
let sorter = new Sorter();
const nbWorkers = 100;
let crawlers = Array.from(new Array(nbWorkers), (x, i) =>
new Crawler({page: i+1}, sorter)
);
new Parallel({tasks: crawlers, field: 'data'}, sorter).run(
(err, results) => {
let {data: [{fact, points: score}]=[]} = results;
console.log(`best fact found (${score} pts) :
${fact}`);
});
}
Pour finir…
Export
par défaut
Portée
bloc
API
étendue
Arrow
function
70. export default function main() {
let sorter = new Sorter();
const nbWorkers = 100;
let crawlers = Array.from(new Array(nbWorkers), (x, i) =>
new Crawler({page: i+1}, sorter)
);
new Parallel({tasks: crawlers, field: 'data'}, sorter).run(
(err, results) => {
let {data: [{fact, points: score}]=[]} = results;
console.log(`best fact found (${score} pts) :
${fact}`);
});
}
Pour finir…
Export
par défaut
Portée
bloc
API
étendue
Arrow
function
De-
structuration
71. export default function main() {
let sorter = new Sorter();
const nbWorkers = 100;
let crawlers = Array.from(new Array(nbWorkers), (x, i) =>
new Crawler({page: i+1}, sorter)
);
new Parallel({tasks: crawlers, field: 'data'}, sorter).run(
(err, results) => {
let {data: [{fact, points: score}]=[]} = results;
console.log(`best fact found (${score} pts) :
${fact}`);
});
}
Pour finir…
Export
par défaut
Portée
bloc
API
étendue
Arrow
function
Template
string
De-
structuration
74. Dès maintenant…enfin presque !
Spécification : ok, implémentation : still going
Utilisez un « compilateur » ES6 vers ES5
Utilisez io.js : NodeJS avec le
dernier Chrome
http://kangax.github.io/compat-table/es6
http://babeljs.i
o
https://github.com/google/traceur-
compiler
77. Crédits photos
Code disponible sur github:
http://github.com/feugy/change-mind-about-js
Fond « speaker’s grid » par Thomas Wang
Slide 3 « code review » par Mickael Zuskin
Slide 23 « Hard Rock lives on » par Dustin Gaffke
Les logos utilisés sont la propriété exclusive de leur
propriétaire
Notes de l'éditeur
2’
Questions à l’auditoire :
- Combien de développeurs ?
- Qui développent en JavaScript ?
- Et qui en sont content ?
Pour ma part, je m’appelle Damien SIMONIN FEUGAS, et je travaille depuis plus de 8 ans chez Worldline.
J’ai pu bosser avec de nombreux langages (Java, JavaScript, ActionScript, Dart, CoffeeScript, Scala), toujours dans un contexte Web (application riche ou serveur d’API).
Ne croyez pas que je soit un « fanboy » du JS : c’est néanmoins le langage que j’utilise le plus au quotidien, et il à acquis un statut incontournable dans l’écosystème Web.
C’est pourquoi il me semble important de vous apportez quelques clés pour comprendre son évolution, et pourquoi pas, vous donner envie de l’utiliser dans vos projets.
Si vous avez des questions, n’hésitez pas à m’interrompre, plutôt que d’attendre la fin de la présentation.
2’
Questions à l’auditoire :
- Combien de développeurs ?
- Qui développent en JavaScript ?
- Et qui en sont content ?
Pour ma part, je m’appelle Damien SIMONIN FEUGAS, et je travaille depuis plus de 8 ans chez Worldline.
J’ai pu bosser avec de nombreux langages (Java, JavaScript, ActionScript, Dart, CoffeeScript, Scala), toujours dans un contexte Web (application riche ou serveur d’API).
Ne croyez pas que je soit un « fanboy » du JS : c’est néanmoins le langage que j’utilise le plus au quotidien, et il à acquis un statut incontournable dans l’écosystème Web.
C’est pourquoi il me semble important de vous apportez quelques clés pour comprendre son évolution, et pourquoi pas, vous donner envie de l’utiliser dans vos projets.
Si vous avez des questions, n’hésitez pas à m’interrompre, plutôt que d’attendre la fin de la présentation.
2’
On « découvre » JavaScript souvent par biais de la dynamisation de page Web statiques.
Le JavaScript n’est pas « Orienté Objet » : il est « prototypé », une notion faussement similaire.
Cette différence est l’un des facteur qui explique le désamour des développeurs pour ce langage
2’
On « découvre » JavaScript souvent par biais de la dynamisation de page Web statiques.
Le JavaScript n’est pas « Orienté Objet » : il est « prototypé », une notion faussement similaire.
Cette différence est l’un des facteur qui explique le désamour des développeurs pour ce langage
2’
On « découvre » JavaScript souvent par biais de la dynamisation de page Web statiques.
Le JavaScript n’est pas « Orienté Objet » : il est « prototypé », une notion faussement similaire.
Cette différence est l’un des facteur qui explique le désamour des développeurs pour ce langage
3’
Depuis 2009, NodeJS balaie les idées reçues sur JavaScript :
De nouveau un langage coté serveur (A l’origine, Netscape l’utilisait déjà coté serveur http://en.wikipedia.org/wiki/JavaScript#Server-side_JavaScript)
Utilisé par des entreprises pour des application de production critique (Walmart, eBay, Paypal, LinkedIn…)
Adopté par une très vaste communauté
La promesse du Full-stack (même langage coté client et serveur) pour des équipes de développement polyvalentes
Les travaux de l’organisme de standardisation Ecma ouvrent de nouveaux horizons :
Plusieurs paradigmes (impératif, fonctionnel, orienté-objet)
Un enrichissement significatif des librairies de bases (notamment les collections)
Des fonctionnalités modernes enfin intégrées au langage
3’
Depuis 2009, NodeJS balaie les idées reçues sur JavaScript :
De nouveau un langage coté serveur (A l’origine, Netscape l’utilisait déjà coté serveur http://en.wikipedia.org/wiki/JavaScript#Server-side_JavaScript)
Utilisé par des entreprises pour des application de production critique (Walmart, eBay, Paypal, LinkedIn…)
Adopté par une très vaste communauté
La promesse du Full-stack (même langage coté client et serveur) pour des équipes de développement polyvalentes
Les travaux de l’organisme de standardisation Ecma ouvrent de nouveaux horizons :
Plusieurs paradigmes (impératif, fonctionnel, orienté-objet)
Un enrichissement significatif des librairies de bases (notamment les collections)
Des fonctionnalités modernes enfin intégrées au langage
5’
Pour illustrer les différentes améliorations de ES6, j’ai simplifié un cas réel.
Pilot est un ordonnanceur de tâches.
Il sert à lancer des tâches d’analyse de données en spark sur un cluster, à faire le reporting (avancement, résultat final) et à assurer le passage de résultats intermédiaire d’une tâche à l’autre.
Pour cette présentation, j’ai créé un job simple qui récupère environ 10 000 citations du site ChuckNorrisFacts.fr, et sélectionne la plus populaire.
Pilot se compose de 2 classes de base :
Task est la classe abstraite :
Méthode run() pour exécuter la tâche, avec un callback lorsque le traitement est terminé
Un attribut next, qui pointe sur l’étape suivante, automatiquement appelée à la fin du traitement par run()
Des attributs start et end, automatiquement rempli lorsque le traitement démarre et se termine
Une méthode _execute(), à implémenter, qui contient le traitement
Parallel est une tâche dont l’implémentation est de lancer simultanément plusieurs sous-tâches (attribut tasks) et de regrouper leurs résultat (attribut field) avant de le passer à la tâche suivante.
J’ai réalisé deux classes filles :
Crawler fait une requête GET sur l’API du site, pour récupérer une page de citation
Sorter sélectionne la citation la plus populaire dans un tableau de citations
Notre job consistera a lancer plusieurs couple Crawler + Sorter en parallèle, et d’appliquer un ultime Sorter à la fin.
Parallel ((Crawler 1 > Sorter) | (Crawler 2 > Sorter) | …) > Sorter
5’
Pour illustrer les différentes améliorations de ES6, j’ai simplifié un cas réel.
Pilot est un ordonnanceur de tâches.
Il sert à lancer des tâches d’analyse de données en spark sur un cluster, à faire le reporting (avancement, résultat final) et à assurer le passage de résultats intermédiaire d’une tâche à l’autre.
Pour cette présentation, j’ai créé un job simple qui récupère environ 10 000 citations du site ChuckNorrisFacts.fr, et sélectionne la plus populaire.
Pilot se compose de 2 classes de base :
Task est la classe abstraite :
Méthode run() pour exécuter la tâche, avec un callback lorsque le traitement est terminé
Un attribut next, qui pointe sur l’étape suivante, automatiquement appelée à la fin du traitement par run()
Des attributs start et end, automatiquement rempli lorsque le traitement démarre et se termine
Une méthode _execute(), à implémenter, qui contient le traitement
Parallel est une tâche dont l’implémentation est de lancer simultanément plusieurs sous-tâches (attribut tasks) et de regrouper leurs résultat (attribut field) avant de le passer à la tâche suivante.
J’ai réalisé deux classes filles :
Crawler fait une requête GET sur l’API du site, pour récupérer une page de citation
Sorter sélectionne la citation la plus populaire dans un tableau de citations
Notre job consistera a lancer plusieurs couple Crawler + Sorter en parallèle, et d’appliquer un ultime Sorter à la fin.
Parallel ((Crawler 1 > Sorter) | (Crawler 2 > Sorter) | …) > Sorter
5’
Pour illustrer les différentes améliorations de ES6, j’ai simplifié un cas réel.
Pilot est un ordonnanceur de tâches.
Il sert à lancer des tâches d’analyse de données en spark sur un cluster, à faire le reporting (avancement, résultat final) et à assurer le passage de résultats intermédiaire d’une tâche à l’autre.
Pour cette présentation, j’ai créé un job simple qui récupère environ 10 000 citations du site ChuckNorrisFacts.fr, et sélectionne la plus populaire.
Pilot se compose de 2 classes de base :
Task est la classe abstraite :
Méthode run() pour exécuter la tâche, avec un callback lorsque le traitement est terminé
Un attribut next, qui pointe sur l’étape suivante, automatiquement appelée à la fin du traitement par run()
Des attributs start et end, automatiquement rempli lorsque le traitement démarre et se termine
Une méthode _execute(), à implémenter, qui contient le traitement
Parallel est une tâche dont l’implémentation est de lancer simultanément plusieurs sous-tâches (attribut tasks) et de regrouper leurs résultat (attribut field) avant de le passer à la tâche suivante.
J’ai réalisé deux classes filles :
Crawler fait une requête GET sur l’API du site, pour récupérer une page de citation
Sorter sélectionne la citation la plus populaire dans un tableau de citations
Notre job consistera a lancer plusieurs couple Crawler + Sorter en parallèle, et d’appliquer un ultime Sorter à la fin.
Parallel ((Crawler 1 > Sorter) | (Crawler 2 > Sorter) | …) > Sorter
12’ passées
En écrivant les classes Task et Parallel, nous allons voir les mécanismes qui manquaient encore cruellement à JavaScript. Avec ES6, il se hisse enfin à la hauteur des autres langages modernes !
2’
Commençons par l’écriture de la classe Task, dans un fichier task.js.
La nouvelle syntaxe pour les classe permet d’isoler le code du constructeur, de déclarer des méthodes de classe et d’instance (notez l’absence du mot clé function), et même des getter et setter.
Un getter s’utilise comme un attribut en lecture seul, un setter comme un attribut en écriture seule.
La classe Task aura besoin d’un constructeur avec le nom de la tâche et son éventuelle tâche suivante.
On surcharge la méthode toString(), et on créera une méthode de classe display() pour afficher la tâche et ses suivantes.
Le getter duration permet de calculer la durée à partir des attributs start et end, si la tâche à été démarrée avec run()
Remarques:
Il est impossible de nommer une méthode constructor
La déclaration des méthodes utilisent une syntaxe abrégée, comme on le verra dans les littéraux objets
Dans les méthodes à échelle de classe on ne peut pas utiliser this
Aucun contrôle de la visibilité : tout est public
Il ne s’agit que de sucre syntaxique : la classe Task est toujours une fonction dont on a enrichi le prototype.
La fourniture de ces mots clé rend la chose aisée, standardise l’opération, et l’implémentation sera libre d’évoluer à l’avenir.
2’
Commençons par l’écriture de la classe Task, dans un fichier task.js.
La nouvelle syntaxe pour les classe permet d’isoler le code du constructeur, de déclarer des méthodes de classe et d’instance (notez l’absence du mot clé function), et même des getter et setter.
Un getter s’utilise comme un attribut en lecture seul, un setter comme un attribut en écriture seule.
La classe Task aura besoin d’un constructeur avec le nom de la tâche et son éventuelle tâche suivante.
On surcharge la méthode toString(), et on créera une méthode de classe display() pour afficher la tâche et ses suivantes.
Le getter duration permet de calculer la durée à partir des attributs start et end, si la tâche à été démarrée avec run()
Remarques:
Il est impossible de nommer une méthode constructor
La déclaration des méthodes utilisent une syntaxe abrégée, comme on le verra dans les littéraux objets
Dans les méthodes à échelle de classe on ne peut pas utiliser this
Aucun contrôle de la visibilité : tout est public
Il ne s’agit que de sucre syntaxique : la classe Task est toujours une fonction dont on a enrichi le prototype.
La fourniture de ces mots clé rend la chose aisée, standardise l’opération, et l’implémentation sera libre d’évoluer à l’avenir.
2’
Commençons par l’écriture de la classe Task, dans un fichier task.js.
La nouvelle syntaxe pour les classe permet d’isoler le code du constructeur, de déclarer des méthodes de classe et d’instance (notez l’absence du mot clé function), et même des getter et setter.
Un getter s’utilise comme un attribut en lecture seul, un setter comme un attribut en écriture seule.
La classe Task aura besoin d’un constructeur avec le nom de la tâche et son éventuelle tâche suivante.
On surcharge la méthode toString(), et on créera une méthode de classe display() pour afficher la tâche et ses suivantes.
Le getter duration permet de calculer la durée à partir des attributs start et end, si la tâche à été démarrée avec run()
Remarques:
Il est impossible de nommer une méthode constructor
La déclaration des méthodes utilisent une syntaxe abrégée, comme on le verra dans les littéraux objets
Dans les méthodes à échelle de classe on ne peut pas utiliser this
Aucun contrôle de la visibilité : tout est public
Il ne s’agit que de sucre syntaxique : la classe Task est toujours une fonction dont on a enrichi le prototype.
La fourniture de ces mots clé rend la chose aisée, standardise l’opération, et l’implémentation sera libre d’évoluer à l’avenir.
2’
Commençons par l’écriture de la classe Task, dans un fichier task.js.
La nouvelle syntaxe pour les classe permet d’isoler le code du constructeur, de déclarer des méthodes de classe et d’instance (notez l’absence du mot clé function), et même des getter et setter.
Un getter s’utilise comme un attribut en lecture seul, un setter comme un attribut en écriture seule.
La classe Task aura besoin d’un constructeur avec le nom de la tâche et son éventuelle tâche suivante.
On surcharge la méthode toString(), et on créera une méthode de classe display() pour afficher la tâche et ses suivantes.
Le getter duration permet de calculer la durée à partir des attributs start et end, si la tâche à été démarrée avec run()
Remarques:
Il est impossible de nommer une méthode constructor
La déclaration des méthodes utilisent une syntaxe abrégée, comme on le verra dans les littéraux objets
Dans les méthodes à échelle de classe on ne peut pas utiliser this
Aucun contrôle de la visibilité : tout est public
Il ne s’agit que de sucre syntaxique : la classe Task est toujours une fonction dont on a enrichi le prototype.
La fourniture de ces mots clé rend la chose aisée, standardise l’opération, et l’implémentation sera libre d’évoluer à l’avenir.
2’
Commençons par l’écriture de la classe Task, dans un fichier task.js.
La nouvelle syntaxe pour les classe permet d’isoler le code du constructeur, de déclarer des méthodes de classe et d’instance (notez l’absence du mot clé function), et même des getter et setter.
Un getter s’utilise comme un attribut en lecture seul, un setter comme un attribut en écriture seule.
La classe Task aura besoin d’un constructeur avec le nom de la tâche et son éventuelle tâche suivante.
On surcharge la méthode toString(), et on créera une méthode de classe display() pour afficher la tâche et ses suivantes.
Le getter duration permet de calculer la durée à partir des attributs start et end, si la tâche à été démarrée avec run()
Remarques:
Il est impossible de nommer une méthode constructor
La déclaration des méthodes utilisent une syntaxe abrégée, comme on le verra dans les littéraux objets
Dans les méthodes à échelle de classe on ne peut pas utiliser this
Aucun contrôle de la visibilité : tout est public
Il ne s’agit que de sucre syntaxique : la classe Task est toujours une fonction dont on a enrichi le prototype.
La fourniture de ces mots clé rend la chose aisée, standardise l’opération, et l’implémentation sera libre d’évoluer à l’avenir.
2’
Voyons immédiatement l’implémentation de la méthode toString(), qui utilise l’interpolation des chaîne de caractères.
Du pur sucre syntaxique : en JS 1.8, on aurait simplement écrit :
toString() {
var className = this.constructor.name;
return className + ' – ' + this.name;
}
On peut mettre n’importe quel code (valide au moment de l’exécution) à l’intérieur des placeholders,
2’
Voyons immédiatement l’implémentation de la méthode toString(), qui utilise l’interpolation des chaîne de caractères.
Du pur sucre syntaxique : en JS 1.8, on aurait simplement écrit :
toString() {
var className = this.constructor.name;
return className + ' – ' + this.name;
}
On peut mettre n’importe quel code (valide au moment de l’exécution) à l’intérieur des placeholders,
2’
Voyons immédiatement l’implémentation de la méthode toString(), qui utilise l’interpolation des chaîne de caractères.
Du pur sucre syntaxique : en JS 1.8, on aurait simplement écrit :
toString() {
var className = this.constructor.name;
return className + ' – ' + this.name;
}
On peut mettre n’importe quel code (valide au moment de l’exécution) à l’intérieur des placeholders,
2’
Voyons immédiatement l’implémentation de la méthode toString(), qui utilise l’interpolation des chaîne de caractères.
Du pur sucre syntaxique : en JS 1.8, on aurait simplement écrit :
toString() {
var className = this.constructor.name;
return className + ' – ' + this.name;
}
On peut mettre n’importe quel code (valide au moment de l’exécution) à l’intérieur des placeholders,
2’
Les développeurs JS auront remarqués que dans toString(), j’ai déclaré une variable, mais pas avec le mot-clé habituel (var)
L’interpréteur JS pré-déclare toutes les variables déclarée dans une fonction au début de celle-ci, en leur affectant la valeur undefined : c’est le hoisting (http://blog.wax-o.com/2014/09/comment-le-hoisting-fonctionne-en-javascript-et-pourquoi/).
Ce mécanisme est à l’origine de nombreux bugs, et de styles de programmation bizarre.
Avec let, les variables sont limitée au bloc (boucle itérative, conditionnelle, bloc…), comme dans tous les autres langages !
Remarques :
Attention au masquage d’un identifiant par un autre (shadowing).
Dans une constantes c’est la variable est immuable, pas la valeur.Si la valeur est un objet (un tableau par exemple), on peut toujours la modifier.L’interpréteur interdit seulement la ré-affectation de la variable.
2’
Les développeurs JS auront remarqués que dans toString(), j’ai déclaré une variable, mais pas avec le mot-clé habituel (var)
L’interpréteur JS pré-déclare toutes les variables déclarée dans une fonction au début de celle-ci, en leur affectant la valeur undefined : c’est le hoisting (http://blog.wax-o.com/2014/09/comment-le-hoisting-fonctionne-en-javascript-et-pourquoi/).
Ce mécanisme est à l’origine de nombreux bugs, et de styles de programmation bizarre.
Avec let, les variables sont limitée au bloc (boucle itérative, conditionnelle, bloc…), comme dans tous les autres langages !
Remarques :
Attention au masquage d’un identifiant par un autre (shadowing).
Dans une constantes c’est la variable est immuable, pas la valeur.Si la valeur est un objet (un tableau par exemple), on peut toujours la modifier.L’interpréteur interdit seulement la ré-affectation de la variable.
2’
Les développeurs JS auront remarqués que dans toString(), j’ai déclaré une variable, mais pas avec le mot-clé habituel (var)
L’interpréteur JS pré-déclare toutes les variables déclarée dans une fonction au début de celle-ci, en leur affectant la valeur undefined : c’est le hoisting (http://blog.wax-o.com/2014/09/comment-le-hoisting-fonctionne-en-javascript-et-pourquoi/).
Ce mécanisme est à l’origine de nombreux bugs, et de styles de programmation bizarre.
Avec let, les variables sont limitée au bloc (boucle itérative, conditionnelle, bloc…), comme dans tous les autres langages !
Remarques :
Attention au masquage d’un identifiant par un autre (shadowing).
Dans une constantes c’est la variable est immuable, pas la valeur.Si la valeur est un objet (un tableau par exemple), on peut toujours la modifier.L’interpréteur interdit seulement la ré-affectation de la variable.
2’
Maintenant que nous avons notre classe Task, nous allons créer la classe Parallel dans un fichier parallel.js dédié.
Comment indiquer en JS pur qu’un fichier utilise des symboles déclarés dans un autre ?
C’est impossible ! On peut soit :
Utiliser les balises <script> (balise HTML donc) > scope global, ordre significatif
Utiliser un loader comme RequireJS > librairie tierce, non standard
Utiliser le require NodeJS > nodejs seulement
ES6 apporte 5 nouveaux mot clés pour exporter (export, default) et importer (import, from, as).
Remarques :
Les chemins sont relatifs (sauf librairies tierces des node_modules)
On le symbole importé porte le même nom que le symbole exporté
On peut exporter plusieurs symboles : des fonctions, des classes, des variables, des constantes.
Il n’y a pas d’obligation de faire une classe par fichier.
Le module est un bloc : ainsi les variables déclarées dans le module et non exportées sont de-facto privées.
Les variable globale d’un module reste privées également.
2’
Maintenant que nous avons notre classe Task, nous allons créer la classe Parallel dans un fichier parallel.js dédié.
Comment indiquer en JS pur qu’un fichier utilise des symboles déclarés dans un autre ?
C’est impossible ! On peut soit :
Utiliser les balises <script> (balise HTML donc) > scope global, ordre significatif
Utiliser un loader comme RequireJS > librairie tierce, non standard
Utiliser le require NodeJS > nodejs seulement
ES6 apporte 5 nouveaux mot clés pour exporter (export, default) et importer (import, from, as).
Remarques :
Les chemins sont relatifs (sauf librairies tierces des node_modules)
On le symbole importé porte le même nom que le symbole exporté
On peut exporter plusieurs symboles : des fonctions, des classes, des variables, des constantes.
Il n’y a pas d’obligation de faire une classe par fichier.
Le module est un bloc : ainsi les variables déclarées dans le module et non exportées sont de-facto privées.
Les variable globale d’un module reste privées également.
1’
Maintenant que nous avons importé la classe Task dans le fichier parallel.js, nous pouvons déclarer Parallel qui étend Task.
Dans une méthode classique, super pointe sur le prototype de la classe mère : on peut donc étendre les méthodes, on les surcharger purement et simplement.
Remarques :
On ne peut pas utiliser this dans le constructeur avant d’avoir invoqué le constructeur hérité.
Héritage simple, sans notion d’interface ou de mixins. Il est possible de combiner à la main différents prototype au moment de l’héritage
C’est une volonté du groupe de travail d’introduire les concepts petit à petit, pour laisser le temps aux VM de les implémenter (voir la réponse de Rauschmayer à ce sujet : https://mail.mozilla.org/pipermail/es-discuss/2013-June/031608.html)
1’
Maintenant que nous avons importé la classe Task dans le fichier parallel.js, nous pouvons déclarer Parallel qui étend Task.
Dans une méthode classique, super pointe sur le prototype de la classe mère : on peut donc étendre les méthodes, on les surcharger purement et simplement.
Remarques :
On ne peut pas utiliser this dans le constructeur avant d’avoir invoqué le constructeur hérité.
Héritage simple, sans notion d’interface ou de mixins. Il est possible de combiner à la main différents prototype au moment de l’héritage
C’est une volonté du groupe de travail d’introduire les concepts petit à petit, pour laisser le temps aux VM de les implémenter (voir la réponse de Rauschmayer à ce sujet : https://mail.mozilla.org/pipermail/es-discuss/2013-June/031608.html)
1’
Maintenant que nous avons importé la classe Task dans le fichier parallel.js, nous pouvons déclarer Parallel qui étend Task.
Dans une méthode classique, super pointe sur le prototype de la classe mère : on peut donc étendre les méthodes, on les surcharger purement et simplement.
Remarques :
On ne peut pas utiliser this dans le constructeur avant d’avoir invoqué le constructeur hérité.
Héritage simple, sans notion d’interface ou de mixins. Il est possible de combiner à la main différents prototype au moment de l’héritage
C’est une volonté du groupe de travail d’introduire les concepts petit à petit, pour laisser le temps aux VM de les implémenter (voir la réponse de Rauschmayer à ce sujet : https://mail.mozilla.org/pipermail/es-discuss/2013-June/031608.html)
1’
Maintenant que nous avons importé la classe Task dans le fichier parallel.js, nous pouvons déclarer Parallel qui étend Task.
Dans une méthode classique, super pointe sur le prototype de la classe mère : on peut donc étendre les méthodes, on les surcharger purement et simplement.
Remarques :
On ne peut pas utiliser this dans le constructeur avant d’avoir invoqué le constructeur hérité.
Héritage simple, sans notion d’interface ou de mixins. Il est possible de combiner à la main différents prototype au moment de l’héritage
C’est une volonté du groupe de travail d’introduire les concepts petit à petit, pour laisser le temps aux VM de les implémenter (voir la réponse de Rauschmayer à ce sujet : https://mail.mozilla.org/pipermail/es-discuss/2013-June/031608.html)
21’ passées
Nous avons notre structure de base en 2 fichiers, voyons maintenant le l’exécution d’une tâche et notamment les tâches en parallèle.
2’
Revenons sur le constructeur de Task.
On y déclare un paramètre avec une valeur par défaut. Le constructeur peut être appelé avec deux paramètres (un nom et une tâche suivante) ou un seul (un nom) : la tâche suivante sera automatiquement nulle.
Enfin, pour initialiser les attributs, on utilise la fonction Object.assign (nouvelle en ES6) et un littéral objet.
La fonction Object.assign fait une copie d’un objet dans un autre (équivalent de extendsOwn de underscore et assign de lodash)
Le second paramètre est un littéral objet avec deux propriétés raccourices: next et name
Remarques :
Les valeurs par défaut s’applique sur les « derniers » paramètres : name ne peut pas avoir de valeur par défaut si next n’en a pas une aussi.
Il existe aussi des propriétés calculée : le nom de la propriété est le résultat d’une expression. Nous verrons un exemple plus tard
2’
Revenons sur le constructeur de Task.
On y déclare un paramètre avec une valeur par défaut. Le constructeur peut être appelé avec deux paramètres (un nom et une tâche suivante) ou un seul (un nom) : la tâche suivante sera automatiquement nulle.
Enfin, pour initialiser les attributs, on utilise la fonction Object.assign (nouvelle en ES6) et un littéral objet.
La fonction Object.assign fait une copie d’un objet dans un autre (équivalent de extendsOwn de underscore et assign de lodash)
Le second paramètre est un littéral objet avec deux propriétés raccourices: next et name
Remarques :
Les valeurs par défaut s’applique sur les « derniers » paramètres : name ne peut pas avoir de valeur par défaut si next n’en a pas une aussi.
Il existe aussi des propriétés calculée : le nom de la propriété est le résultat d’une expression. Nous verrons un exemple plus tard
2’
Revenons sur le constructeur de Task.
On y déclare un paramètre avec une valeur par défaut. Le constructeur peut être appelé avec deux paramètres (un nom et une tâche suivante) ou un seul (un nom) : la tâche suivante sera automatiquement nulle.
Enfin, pour initialiser les attributs, on utilise la fonction Object.assign (nouvelle en ES6) et un littéral objet.
La fonction Object.assign fait une copie d’un objet dans un autre (équivalent de extendsOwn de underscore et assign de lodash)
Le second paramètre est un littéral objet avec deux propriétés raccourices: next et name
Remarques :
Les valeurs par défaut s’applique sur les « derniers » paramètres : name ne peut pas avoir de valeur par défaut si next n’en a pas une aussi.
Il existe aussi des propriétés calculée : le nom de la propriété est le résultat d’une expression. Nous verrons un exemple plus tard
2’
Revenons sur le constructeur de Task.
On y déclare un paramètre avec une valeur par défaut. Le constructeur peut être appelé avec deux paramètres (un nom et une tâche suivante) ou un seul (un nom) : la tâche suivante sera automatiquement nulle.
Enfin, pour initialiser les attributs, on utilise la fonction Object.assign (nouvelle en ES6) et un littéral objet.
La fonction Object.assign fait une copie d’un objet dans un autre (équivalent de extendsOwn de underscore et assign de lodash)
Le second paramètre est un littéral objet avec deux propriétés raccourices: next et name
Remarques :
Les valeurs par défaut s’applique sur les « derniers » paramètres : name ne peut pas avoir de valeur par défaut si next n’en a pas une aussi.
Il existe aussi des propriétés calculée : le nom de la propriété est le résultat d’une expression. Nous verrons un exemple plus tard
2’
Revenons sur le constructeur de Task.
On y déclare un paramètre avec une valeur par défaut. Le constructeur peut être appelé avec deux paramètres (un nom et une tâche suivante) ou un seul (un nom) : la tâche suivante sera automatiquement nulle.
Enfin, pour initialiser les attributs, on utilise la fonction Object.assign (nouvelle en ES6) et un littéral objet.
La fonction Object.assign fait une copie d’un objet dans un autre (équivalent de extendsOwn de underscore et assign de lodash)
Le second paramètre est un littéral objet avec deux propriétés raccourices: next et name
Remarques :
Les valeurs par défaut s’applique sur les « derniers » paramètres : name ne peut pas avoir de valeur par défaut si next n’en a pas une aussi.
Il existe aussi des propriétés calculée : le nom de la propriété est le résultat d’une expression. Nous verrons un exemple plus tard
2’
Revenons sur le constructeur de Task.
On y déclare un paramètre avec une valeur par défaut. Le constructeur peut être appelé avec deux paramètres (un nom et une tâche suivante) ou un seul (un nom) : la tâche suivante sera automatiquement nulle.
Enfin, pour initialiser les attributs, on utilise la fonction Object.assign (nouvelle en ES6) et un littéral objet.
La fonction Object.assign fait une copie d’un objet dans un autre (équivalent de extendsOwn de underscore et assign de lodash)
Le second paramètre est un littéral objet avec deux propriétés raccourices: next et name
Remarques :
Les valeurs par défaut s’applique sur les « derniers » paramètres : name ne peut pas avoir de valeur par défaut si next n’en a pas une aussi.
Il existe aussi des propriétés calculée : le nom de la propriété est le résultat d’une expression. Nous verrons un exemple plus tard
2’
Revenons sur le constructeur de Task.
On y déclare un paramètre avec une valeur par défaut. Le constructeur peut être appelé avec deux paramètres (un nom et une tâche suivante) ou un seul (un nom) : la tâche suivante sera automatiquement nulle.
Enfin, pour initialiser les attributs, on utilise la fonction Object.assign (nouvelle en ES6) et un littéral objet.
La fonction Object.assign fait une copie d’un objet dans un autre (équivalent de extendsOwn de underscore et assign de lodash)
Le second paramètre est un littéral objet avec deux propriétés raccourices: next et name
Remarques :
Les valeurs par défaut s’applique sur les « derniers » paramètres : name ne peut pas avoir de valeur par défaut si next n’en a pas une aussi.
Il existe aussi des propriétés calculée : le nom de la propriété est le résultat d’une expression. Nous verrons un exemple plus tard
2’
Revenons sur le constructeur de Task.
On y déclare un paramètre avec une valeur par défaut. Le constructeur peut être appelé avec deux paramètres (un nom et une tâche suivante) ou un seul (un nom) : la tâche suivante sera automatiquement nulle.
Enfin, pour initialiser les attributs, on utilise la fonction Object.assign (nouvelle en ES6) et un littéral objet.
La fonction Object.assign fait une copie d’un objet dans un autre (équivalent de extendsOwn de underscore et assign de lodash)
Le second paramètre est un littéral objet avec deux propriétés raccourices: next et name
Remarques :
Les valeurs par défaut s’applique sur les « derniers » paramètres : name ne peut pas avoir de valeur par défaut si next n’en a pas une aussi.
Il existe aussi des propriétés calculée : le nom de la propriété est le résultat d’une expression. Nous verrons un exemple plus tard
2’
Revenons sur le constructeur de Task.
On y déclare un paramètre avec une valeur par défaut. Le constructeur peut être appelé avec deux paramètres (un nom et une tâche suivante) ou un seul (un nom) : la tâche suivante sera automatiquement nulle.
Enfin, pour initialiser les attributs, on utilise la fonction Object.assign (nouvelle en ES6) et un littéral objet.
La fonction Object.assign fait une copie d’un objet dans un autre (équivalent de extendsOwn de underscore et assign de lodash)
Le second paramètre est un littéral objet avec deux propriétés raccourices: next et name
Remarques :
Les valeurs par défaut s’applique sur les « derniers » paramètres : name ne peut pas avoir de valeur par défaut si next n’en a pas une aussi.
Il existe aussi des propriétés calculée : le nom de la propriété est le résultat d’une expression. Nous verrons un exemple plus tard
2’
Revenons sur le constructeur de Task.
On y déclare un paramètre avec une valeur par défaut. Le constructeur peut être appelé avec deux paramètres (un nom et une tâche suivante) ou un seul (un nom) : la tâche suivante sera automatiquement nulle.
Enfin, pour initialiser les attributs, on utilise la fonction Object.assign (nouvelle en ES6) et un littéral objet.
La fonction Object.assign fait une copie d’un objet dans un autre (équivalent de extendsOwn de underscore et assign de lodash)
Le second paramètre est un littéral objet avec deux propriétés raccourices: next et name
Remarques :
Les valeurs par défaut s’applique sur les « derniers » paramètres : name ne peut pas avoir de valeur par défaut si next n’en a pas une aussi.
Il existe aussi des propriétés calculée : le nom de la propriété est le résultat d’une expression. Nous verrons un exemple plus tard
2’
La méthode run() est celle qui lance l’exécution d’un tâche et qui attends sa completion.
Lorsque l’exécution (méthode _execute(), à implementer dans les classes filles) et terminée, lance la tâche suivante si besoin (et s’il n’y a pas d’erreur).
Le « Rest operator » simplifie considérablement l’utilisation de arguments.
La méthode run aura deux signatures possibles :
run(params: Object, done: Function)
run(done: Function)
Les fonctions fléchées ont deux objectifs :
Rendre le code plus concis
Conserver le contexte d’exécution au moment de l’appel : utilisation de Function.bind()
Remarques :
- seul le dernier paramètre peut avoir cette opérateur
2’
La méthode run() est celle qui lance l’exécution d’un tâche et qui attends sa completion.
Lorsque l’exécution (méthode _execute(), à implementer dans les classes filles) et terminée, lance la tâche suivante si besoin (et s’il n’y a pas d’erreur).
Le « Rest operator » simplifie considérablement l’utilisation de arguments.
La méthode run aura deux signatures possibles :
run(params: Object, done: Function)
run(done: Function)
Les fonctions fléchées ont deux objectifs :
Rendre le code plus concis
Conserver le contexte d’exécution au moment de l’appel : utilisation de Function.bind()
Remarques :
- seul le dernier paramètre peut avoir cette opérateur
2’
La méthode run() est celle qui lance l’exécution d’un tâche et qui attends sa completion.
Lorsque l’exécution (méthode _execute(), à implementer dans les classes filles) et terminée, lance la tâche suivante si besoin (et s’il n’y a pas d’erreur).
Le « Rest operator » simplifie considérablement l’utilisation de arguments.
La méthode run aura deux signatures possibles :
run(params: Object, done: Function)
run(done: Function)
Les fonctions fléchées ont deux objectifs :
Rendre le code plus concis
Conserver le contexte d’exécution au moment de l’appel : utilisation de Function.bind()
Remarques :
- seul le dernier paramètre peut avoir cette opérateur
2’
La méthode run() est celle qui lance l’exécution d’un tâche et qui attends sa completion.
Lorsque l’exécution (méthode _execute(), à implementer dans les classes filles) et terminée, lance la tâche suivante si besoin (et s’il n’y a pas d’erreur).
Le « Rest operator » simplifie considérablement l’utilisation de arguments.
La méthode run aura deux signatures possibles :
run(params: Object, done: Function)
run(done: Function)
Les fonctions fléchées ont deux objectifs :
Rendre le code plus concis
Conserver le contexte d’exécution au moment de l’appel : utilisation de Function.bind()
Remarques :
- seul le dernier paramètre peut avoir cette opérateur
2’
La méthode run() est celle qui lance l’exécution d’un tâche et qui attends sa completion.
Lorsque l’exécution (méthode _execute(), à implementer dans les classes filles) et terminée, lance la tâche suivante si besoin (et s’il n’y a pas d’erreur).
Le « Rest operator » simplifie considérablement l’utilisation de arguments.
La méthode run aura deux signatures possibles :
run(params: Object, done: Function)
run(done: Function)
Les fonctions fléchées ont deux objectifs :
Rendre le code plus concis
Conserver le contexte d’exécution au moment de l’appel : utilisation de Function.bind()
Remarques :
- seul le dernier paramètre peut avoir cette opérateur
2’
La méthode run() est celle qui lance l’exécution d’un tâche et qui attends sa completion.
Lorsque l’exécution (méthode _execute(), à implementer dans les classes filles) et terminée, lance la tâche suivante si besoin (et s’il n’y a pas d’erreur).
Le « Rest operator » simplifie considérablement l’utilisation de arguments.
La méthode run aura deux signatures possibles :
run(params: Object, done: Function)
run(done: Function)
Les fonctions fléchées ont deux objectifs :
Rendre le code plus concis
Conserver le contexte d’exécution au moment de l’appel : utilisation de Function.bind()
Remarques :
- seul le dernier paramètre peut avoir cette opérateur
1’
Venons enfin à l’implémentation de Parallel._execute() : celle qui lance les tâches simultanées.
Elle stocke tous les résultats présent dans le champ this.field dans un tableau et le renvoi lorsque toutes les tâches sont terminées
Remarques :
Le for-in s’applique sur les objets, et ne parcours que les propriétés itérables, sans garantie d’ordre.
for-of est une altérnative à Array.forEach() pour les tableaux
1’
Venons enfin à l’implémentation de Parallel._execute() : celle qui lance les tâches simultanées.
Elle stocke tous les résultats présent dans le champ this.field dans un tableau et le renvoi lorsque toutes les tâches sont terminées
Remarques :
Le for-in s’applique sur les objets, et ne parcours que les propriétés itérables, sans garantie d’ordre.
for-of est une altérnative à Array.forEach() pour les tableaux
1’
Venons enfin à l’implémentation de Parallel._execute() : celle qui lance les tâches simultanées.
Elle stocke tous les résultats présent dans le champ this.field dans un tableau et le renvoi lorsque toutes les tâches sont terminées
Remarques :
Le for-in s’applique sur les objets, et ne parcours que les propriétés itérables, sans garantie d’ordre.
for-of est une altérnative à Array.forEach() pour les tableaux
1’
Venons enfin à l’implémentation de Parallel._execute() : celle qui lance les tâches simultanées.
Elle stocke tous les résultats présent dans le champ this.field dans un tableau et le renvoi lorsque toutes les tâches sont terminées
Remarques :
Le for-in s’applique sur les objets, et ne parcours que les propriétés itérables, sans garantie d’ordre.
for-of est une altérnative à Array.forEach() pour les tableaux
26’ passées
Il est temps de passer sur la récupération des cittations sur Chuck Norris : les classes Crawler et Sorter, réunies dans le même fichier
1’
Notre fichier chuck.js contient nos 2 classes, et nécessite l’import de symboles déclarés dans d’autres fichiers.
En particulier, le fichier utils.js qui regroupe des fonctions de parsing des citations, et de formatage des paramètres.
Remarques
Lorsqu’on importe N symboles, on les sépare par des virgules
L’utilisation d’alias permet d’éviter les conflits de nommage (2 dépendances exportant un symbole de même nom)
Le nom du symbole par défaut importé peut différer de celui exporté
Sources : http://www.2ality.com/2014/09/es6-modules-final.html
1’
Notre fichier chuck.js contient nos 2 classes, et nécessite l’import de symboles déclarés dans d’autres fichiers.
En particulier, le fichier utils.js qui regroupe des fonctions de parsing des citations, et de formatage des paramètres.
Remarques
Lorsqu’on importe N symboles, on les sépare par des virgules
L’utilisation d’alias permet d’éviter les conflits de nommage (2 dépendances exportant un symbole de même nom)
Le nom du symbole par défaut importé peut différer de celui exporté
Sources : http://www.2ality.com/2014/09/es6-modules-final.html
1’
Notre fichier chuck.js contient nos 2 classes, et nécessite l’import de symboles déclarés dans d’autres fichiers.
En particulier, le fichier utils.js qui regroupe des fonctions de parsing des citations, et de formatage des paramètres.
Remarques
Lorsqu’on importe N symboles, on les sépare par des virgules
L’utilisation d’alias permet d’éviter les conflits de nommage (2 dépendances exportant un symbole de même nom)
Le nom du symbole par défaut importé peut différer de celui exporté
Sources : http://www.2ality.com/2014/09/es6-modules-final.html
1’
Notre fichier chuck.js contient nos 2 classes, et nécessite l’import de symboles déclarés dans d’autres fichiers.
En particulier, le fichier utils.js qui regroupe des fonctions de parsing des citations, et de formatage des paramètres.
Remarques
Lorsqu’on importe N symboles, on les sépare par des virgules
L’utilisation d’alias permet d’éviter les conflits de nommage (2 dépendances exportant un symbole de même nom)
Le nom du symbole par défaut importé peut différer de celui exporté
Sources : http://www.2ality.com/2014/09/es6-modules-final.html
1’
Notre fichier chuck.js contient nos 2 classes, et nécessite l’import de symboles déclarés dans d’autres fichiers.
En particulier, le fichier utils.js qui regroupe des fonctions de parsing des citations, et de formatage des paramètres.
Remarques
Lorsqu’on importe N symboles, on les sépare par des virgules
L’utilisation d’alias permet d’éviter les conflits de nommage (2 dépendances exportant un symbole de même nom)
Le nom du symbole par défaut importé peut différer de celui exporté
Sources : http://www.2ality.com/2014/09/es6-modules-final.html
2’
La classe Crawler implémente une tâche qui récupère les citations d’une page donnée via un appel HTTP à l’API de ChuckNorrisFacts.fr
Le constructeur prends 2 paramètres : les options de l’appel (proxy, timeout, nombre de citations, page…) et l’étape suivante.
Par soucis d’évolutivité, j’ai choisi de ne pas déclarer le paramètre next : si le constructeur de Task venait à prendre d’autres paramètres, il n’y aura aucun impact sur le Crawler, car il les relaie tous, seul le premier à une signification pour lui.
Le « spread operator » réalise l’inverse du « rest operator », ils sont souvent utilisés de concert.
2’
La classe Crawler implémente une tâche qui récupère les citations d’une page donnée via un appel HTTP à l’API de ChuckNorrisFacts.fr
Le constructeur prends 2 paramètres : les options de l’appel (proxy, timeout, nombre de citations, page…) et l’étape suivante.
Par soucis d’évolutivité, j’ai choisi de ne pas déclarer le paramètre next : si le constructeur de Task venait à prendre d’autres paramètres, il n’y aura aucun impact sur le Crawler, car il les relaie tous, seul le premier à une signification pour lui.
Le « spread operator » réalise l’inverse du « rest operator », ils sont souvent utilisés de concert.
2’
La classe Crawler implémente une tâche qui récupère les citations d’une page donnée via un appel HTTP à l’API de ChuckNorrisFacts.fr
Le constructeur prends 2 paramètres : les options de l’appel (proxy, timeout, nombre de citations, page…) et l’étape suivante.
Par soucis d’évolutivité, j’ai choisi de ne pas déclarer le paramètre next : si le constructeur de Task venait à prendre d’autres paramètres, il n’y aura aucun impact sur le Crawler, car il les relaie tous, seul le premier à une signification pour lui.
Le « spread operator » réalise l’inverse du « rest operator », ils sont souvent utilisés de concert.
2’
La classe Crawler implémente une tâche qui récupère les citations d’une page donnée via un appel HTTP à l’API de ChuckNorrisFacts.fr
Le constructeur prends 2 paramètres : les options de l’appel (proxy, timeout, nombre de citations, page…) et l’étape suivante.
Par soucis d’évolutivité, j’ai choisi de ne pas déclarer le paramètre next : si le constructeur de Task venait à prendre d’autres paramètres, il n’y aura aucun impact sur le Crawler, car il les relaie tous, seul le premier à une signification pour lui.
Le « spread operator » réalise l’inverse du « rest operator », ils sont souvent utilisés de concert.
2’
La classe Crawler implémente une tâche qui récupère les citations d’une page donnée via un appel HTTP à l’API de ChuckNorrisFacts.fr
Le constructeur prends 2 paramètres : les options de l’appel (proxy, timeout, nombre de citations, page…) et l’étape suivante.
Par soucis d’évolutivité, j’ai choisi de ne pas déclarer le paramètre next : si le constructeur de Task venait à prendre d’autres paramètres, il n’y aura aucun impact sur le Crawler, car il les relaie tous, seul le premier à une signification pour lui.
Le « spread operator » réalise l’inverse du « rest operator », ils sont souvent utilisés de concert.
2’
La classe Crawler implémente une tâche qui récupère les citations d’une page donnée via un appel HTTP à l’API de ChuckNorrisFacts.fr
Le constructeur prends 2 paramètres : les options de l’appel (proxy, timeout, nombre de citations, page…) et l’étape suivante.
Par soucis d’évolutivité, j’ai choisi de ne pas déclarer le paramètre next : si le constructeur de Task venait à prendre d’autres paramètres, il n’y aura aucun impact sur le Crawler, car il les relaie tous, seul le premier à une signification pour lui.
Le « spread operator » réalise l’inverse du « rest operator », ils sont souvent utilisés de concert.
2’
La classe Crawler implémente une tâche qui récupère les citations d’une page donnée via un appel HTTP à l’API de ChuckNorrisFacts.fr
Le constructeur prends 2 paramètres : les options de l’appel (proxy, timeout, nombre de citations, page…) et l’étape suivante.
Par soucis d’évolutivité, j’ai choisi de ne pas déclarer le paramètre next : si le constructeur de Task venait à prendre d’autres paramètres, il n’y aura aucun impact sur le Crawler, car il les relaie tous, seul le premier à une signification pour lui.
Le « spread operator » réalise l’inverse du « rest operator », ils sont souvent utilisés de concert.
2’
La classe Crawler implémente une tâche qui récupère les citations d’une page donnée via un appel HTTP à l’API de ChuckNorrisFacts.fr
Le constructeur prends 2 paramètres : les options de l’appel (proxy, timeout, nombre de citations, page…) et l’étape suivante.
Par soucis d’évolutivité, j’ai choisi de ne pas déclarer le paramètre next : si le constructeur de Task venait à prendre d’autres paramètres, il n’y aura aucun impact sur le Crawler, car il les relaie tous, seul le premier à une signification pour lui.
Le « spread operator » réalise l’inverse du « rest operator », ils sont souvent utilisés de concert.
2’
Pour terminer, le job complet, qui lance 100 couples (Crawler + Sorter) en parallèle, puis trie les résultats avec un dernier Sorter.
La fonction callback exécutée à la fin du job reçoit la citation en paramètre, encapsulée dans un tableau.
Cette fonction est l’export par défaut du fichier, pour qu’on puisse simplement la lancer.
On n’utilisera que 2 champs de la citation : la déstructuration sert à exploser le retour du Sorter
Remarques:
- La destructuration peut se faire sur un paramètre de fonction, et sur une variable quelconque
- Il est possible d’utiliser des valeurs par défaut lors d’une déstructuration
- On peut avoir des ReferenceError si une des extraction n’est pas possible à cause d’une valeur nulle ou inexistante.
2’
Pour terminer, le job complet, qui lance 100 couples (Crawler + Sorter) en parallèle, puis trie les résultats avec un dernier Sorter.
La fonction callback exécutée à la fin du job reçoit la citation en paramètre, encapsulée dans un tableau.
Cette fonction est l’export par défaut du fichier, pour qu’on puisse simplement la lancer.
On n’utilisera que 2 champs de la citation : la déstructuration sert à exploser le retour du Sorter
Remarques:
- La destructuration peut se faire sur un paramètre de fonction, et sur une variable quelconque
- Il est possible d’utiliser des valeurs par défaut lors d’une déstructuration
- On peut avoir des ReferenceError si une des extraction n’est pas possible à cause d’une valeur nulle ou inexistante.
2’
Pour terminer, le job complet, qui lance 100 couples (Crawler + Sorter) en parallèle, puis trie les résultats avec un dernier Sorter.
La fonction callback exécutée à la fin du job reçoit la citation en paramètre, encapsulée dans un tableau.
Cette fonction est l’export par défaut du fichier, pour qu’on puisse simplement la lancer.
On n’utilisera que 2 champs de la citation : la déstructuration sert à exploser le retour du Sorter
Remarques:
- La destructuration peut se faire sur un paramètre de fonction, et sur une variable quelconque
- Il est possible d’utiliser des valeurs par défaut lors d’une déstructuration
- On peut avoir des ReferenceError si une des extraction n’est pas possible à cause d’une valeur nulle ou inexistante.
2’
Pour terminer, le job complet, qui lance 100 couples (Crawler + Sorter) en parallèle, puis trie les résultats avec un dernier Sorter.
La fonction callback exécutée à la fin du job reçoit la citation en paramètre, encapsulée dans un tableau.
Cette fonction est l’export par défaut du fichier, pour qu’on puisse simplement la lancer.
On n’utilisera que 2 champs de la citation : la déstructuration sert à exploser le retour du Sorter
Remarques:
- La destructuration peut se faire sur un paramètre de fonction, et sur une variable quelconque
- Il est possible d’utiliser des valeurs par défaut lors d’une déstructuration
- On peut avoir des ReferenceError si une des extraction n’est pas possible à cause d’une valeur nulle ou inexistante.
2’
Pour terminer, le job complet, qui lance 100 couples (Crawler + Sorter) en parallèle, puis trie les résultats avec un dernier Sorter.
La fonction callback exécutée à la fin du job reçoit la citation en paramètre, encapsulée dans un tableau.
Cette fonction est l’export par défaut du fichier, pour qu’on puisse simplement la lancer.
On n’utilisera que 2 champs de la citation : la déstructuration sert à exploser le retour du Sorter
Remarques:
- La destructuration peut se faire sur un paramètre de fonction, et sur une variable quelconque
- Il est possible d’utiliser des valeurs par défaut lors d’une déstructuration
- On peut avoir des ReferenceError si une des extraction n’est pas possible à cause d’une valeur nulle ou inexistante.
2’
Pour terminer, le job complet, qui lance 100 couples (Crawler + Sorter) en parallèle, puis trie les résultats avec un dernier Sorter.
La fonction callback exécutée à la fin du job reçoit la citation en paramètre, encapsulée dans un tableau.
Cette fonction est l’export par défaut du fichier, pour qu’on puisse simplement la lancer.
On n’utilisera que 2 champs de la citation : la déstructuration sert à exploser le retour du Sorter
Remarques:
- La destructuration peut se faire sur un paramètre de fonction, et sur une variable quelconque
- Il est possible d’utiliser des valeurs par défaut lors d’une déstructuration
- On peut avoir des ReferenceError si une des extraction n’est pas possible à cause d’une valeur nulle ou inexistante.
1’
32’ passées
2’
Dans mon équipe nous utilisons traceur depuis plus d’un an, sur un projet maintenant en production
Pour cette présentation, j’ai réécrit Pilot avec babel.js.
Io.js active les dernières fonctionnalités ES6 de chrome, malheureusement les modules ne sont pas encore implémentés avec la syntaxe finale.