Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

Async/await avec les générateurs "harmony"

No description
by

Bruno Jouhier

on 30 October 2013

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of Async/await avec les générateurs "harmony"

Async/await avec les générateurs "harmony"
Petite intro
Bruno
Les Générateurs en JavaScript
Un peu d'histoire
Bruno Jouhier
Editeur de logiciels de Gestion
Fondée en 1981
UK, cotée à Londres
1 340 M£ CA
13 400 employés (1 800 en France)
Sage ERP X3
Le produit ERP Mid-Market international de Sage
25+ années de R&D = +ieurs M locs

Rénovation techno en cours depuis 2010, basée sur jquery, node.js et mongodb.

Sortie commerciale V7.1 prévue juin 2014
52 ans
2 startups
13 ans chez Sage

Projets open source
streamline.js
galaxy
node-lol
Sage
Existent dans Firefox depuis 2006 (JavaScript 1.7)

Ré-introduits avec quelques modifications dans EcmaScript 6 (harmony)

Disponibles dans:
node.js (>= 0.11.4)
Chrome Canary (>= 32.0)
Firefox (annoncé par Andy Wingo le 7 octobre)
Késaco
Un nouveau genre de fonctions:
déclarées avec function*
pouvant contenir yield

Avec un comportement spécial:
Le body n'est pas exécuté lorsqu'on appelle la fonction.
A la place, la fonction retourne un "générateur"
Le body est exécuté quand on appelle la méthode "next" du générateur.
"next" n'exécute pas la totalité du body mais s'arrête au premier "yield".
Il faut appeler "next()" à nouveau pour executer jusqu'au "yield" suivant.

Et aussi quelques goodies: yield*, for ... of ...
#1 hello world
function* myFirstGenerator() {
console.log("generator before yield hello".green);
yield "hello";
console.log("generator before yield world".green);
yield "world";
console.log("generator at end".green);
}
#2 fibonacci
#3 tree walker
var tree = {
left: {
left: {
left: { value: 1 },
value: 3,
right: { value: 8 }
},
value: 10,
right: { value: 13 }
},
value: 20,
right: { value: 22 }
};

function* walk(t) {
if (t.left) yield* walk(t.left);
yield t.value;
if (t.right) yield* walk(t.right);
}
function* genFibo() {
var f1 = 0, f2 = 1;
while (true) {
console.log(("genFibo loop: " + f1).green)
yield f1;
var f = f1 + f2; f1 = f2; f2 = f;
}
}
var walker = walk(tree);

for (var v of walker) console.log(v);
console.log("starting program".blue);
var g = myFirstGenerator();
console.log("generator created".blue);
var v1 = g.next();
console.log(("next #1 returned " + JSON.stringify(v1) + "").blue);
var v2 = g.next();
console.log(("next #2 returned " + JSON.stringify(v2) + "").blue);
var v3 = g.next();
console.log(("next #3 returned " + JSON.stringify(v3) + "").blue);

var g = genFibo();

for (var i = 0; i < 10; i++) {
var v = g.next();
console.log(("fibo(" + i + ")=" + v.value).blue);
}
Exemples
En quelques mots
Un génerateur, c'est une fonction dont vous pouvez contrôler l'exécution.

Chaque fois que vous appelez next, la fonction avance jusqu'au prochain yield et vous fournit un résultat intermédiaire.

Un générateur peut produire une suite infinie de valeurs.
L'enfer des callbacks
function archiveOrders(date, cb) {
db.connect(function(err, conn) {
if (err) return cb(err);
conn.query("select * from orders where date < ?", [date], function(err, orders) {
if (err) return cb(err);
helper.each(orders, function(order, next) {
conn.execute("insert into archivedOrders ...", [order.id, ...], function(err) {
if (err) return cb(err);
conn.execute("delete from orders where id=?", [order.id], function(err) {
if (err) return cb(err);
next();
});
});
}, function() {
console.log("orders have been archived");
cb();
});
});
});
}
async function archiveOrders(date) {
var conn = await db.connect();
var orders = await conn.query("select * from orders where date < ?", [date]);
await orders.each(function(order) {
await conn.execute("insert into archivedOrders ...", [order.id, ...]);
await conn.execute("delete from orders where id=?", [order.id]);
});
console.log("orders have been archived");
}
Moins de code
Code plus lisible et plus facile à maintenir
La même chose avec Galaxy
(ne rêvons plus)
function* archiveOrders(date) {
var conn = yield db.connect();
var orders = yield conn.query("select * from orders where date < ?", [date]);
yield orders.forEachStar(function*(order) {
yield conn.execute("insert into archivedOrders ...", [order.id, ...]);
yield conn.execute("delete from orders where id=?", [order.id]);
});
console.log("orders have been archived");
}
async --> function*
await --> yield
function asyncMessage(msg, cb) {
setTimeout(function() {
cb(null, msg);
}, 1000);
}
function resume(g) {
return function(err, result) {
if (err) g.throw (err);
else g.next(result);
};
}
function helloWorld(cb) {
var g = (function *() {
var msg1 = yield asyncMessage("hello ...", resume(g));
console.log(msg1);
var msg2 = yield asyncMessage("... world", resume(g));
console.log(msg2);
cb(null, msg1 + msg2);
})();
g.next();
}

helloWorld(function(err, result) {
console.log("final result: " + result);
})
resume
asyncMessage
helloWorld
yield
g.next(result)
Avec Galaxy
function asyncMessage(msg, cb) {
setTimeout(function() {
cb(null, msg);
}, 1000);
}
var starMessage = galaxy.star(asyncMessage);

function* helloWorld() {
var msg1 = yield starMessage("hello ...");
console.log(msg1);
var msg2 = yield starMessage("... world");
console.log(msg2);
return msg1 + msg2;
}
var helloWorldCb = galaxy.unstar(helloWorld);

helloWorldCb(function(err, result) {
console.log("final result: " + result);
})
asyncMessage(msg, cb)
helloWorldCb(cb)
starMessage(msg)
helloWorld()
callback-land
generators-land
function
function*
galaxy.star
galaxy.unstar
// // // Parallélisons avec galaxy.spin // // //
function* helloWorld() {
var msg1F = galaxy.spin(asyncMessage("hello ..."));
var msg2F = galaxy.spin(asyncMessage("... world"));

var msg1 = yield msg1F();
console.log(msg1);
var msg2 = yield msg2F();
console.log(msg2);

return msg1 + msg2;
}
Réduisons encore le bruit avec streamline.js
function asyncMessage(msg, cb) {
setTimeout(function() {
cb(null, msg);
}, 1000);
}
function helloWorld(_) {
var msg1 = asyncMessage("hello ...", _);
console.log(msg1);
var msg2 = asyncMessage("... world", _);
console.log(msg2);
return msg1 + msg2;
}

helloWorld(function(err, result) {
console.log("final result: " + result);
})
function helloWorld(_) {
var msg1 = asyncMessage("hello ...", _);
console.log(msg1);
var msg2 = asyncMessage("... world", _);
console.log(msg2);
return msg1 + msg2;
}
function helloWorld(_) {
var msg1, msg2;
var __frame = { name: "helloWorld", line: 1 };
return __func(_, this, arguments, helloWorld, 0, __frame,
function __$helloWorld() {
return asyncMessage("hello ...", __cb(_, __frame, 1, 13,
function ___(__0, __1) {
msg1 = __1;
console.log(msg1);
return asyncMessage("... world", __cb(_, __frame, 3, 13,
function ___(__0, __2) {
msg2 = __2;
console.log(msg2);
return _(null, (msg1 + msg2));
}, true));
}, true));
});
};
function helloWorld(_) {
var msg1 = fstreamline__.invoke(null,
asyncMessage, ["hello ...", _], 1);
console.log(msg1);
var msg2 = fstreamline__.invoke(null,
asyncMessage, ["... world", _], 1);
console.log(msg2);
return msg1 + msg2;
}
function* helloWorld(_) {
var msg1 = (yield galaxy.invoke(null,
asyncMessage, ["hello ...", _], 1));
console.log(msg1);
var msg2 = (yield galaxy.invoke(null,
asyncMessage, ["... world", _], 1));
console.log(msg2);
return msg1 + msg2;
}
callbacks
générateurs
fibers
options de pré-processing streamline.js
Quelques liens
https://github.com/jmar777/suspend
https://github.com/spion/genny
https://github.com/creationix/gen-run

https://github.com/bjouhier/galaxy
https://github.com/Sage/streamlinejs
https://gist.github.com/bjouhier/7229244
Quelques outils similaires
Merci pour votre attention
? ? ?
La même chose avec Async / Await
(rêvons un peu)
Comment ça marche ?
Full transcript