Slide 1

Slide 1 text

PROMISES, GENERATORS, ASYNC/AWAIT!

Slide 2

Slide 2 text

CALLBACKS A piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at some convenient time.

Slide 3

Slide 3 text

JQUERY CALLBACK STYLE $(document).ready(function() { $("#foo").on("click", function(event) { $.getJSON("/data.json", function(data) { alert(data); }); }); })

Slide 4

Slide 4 text

NODE.JS CALLBACK STYLE doSomething(param1, param2, function(err, result) { if (err) { // handle error } { // move with result } });

Slide 5

Slide 5 text

CALLBACK HELL router.get('/dashboard', function(req, res) { Stats.getMemoryUsage(function(err, memory) { Stats.getCPUUsage(function(err, cpu) { Stats.getUserRetention(function(err, retention) { res.render('dashboard', { memory: memory, cpu: cpu, retention: retention }); }); }); }); });

Slide 6

Slide 6 text

CALLBACK HELL /2 getData(function(a) { getMoreData(a, function(b) { getMoreData(b, function(c) { getMoreData(c, function(d) { getMoreData(d, function(e) { // ... }); }); }); }); });

Slide 7

Slide 7 text

CALLBACK HELL /3 getData(function(err, a) { if (err) { handleError(err); } else { getMoreData(a, function(err, b) { if (err) { handleError(err); } else { getMoreData(b, function(err, c) { // ... }); } }); } });

Slide 8

Slide 8 text

!

Slide 9

Slide 9 text

SO, WE DON'T BLOCK BUT... > No return/catch > Callback hell > Callback functions tend to become difficult to maintain and debug when nested within long lines of code > Anonymous inline functions in a callback can make reading the call stack very tedious

Slide 10

Slide 10 text

ASYNC.JS A UTILITY MODULE WHICH PROVIDES STRAIGHT-FORWARD, POWERFUL FUNCTIONS FOR WORKING WITH ASYNCHRONOUS JAVASCRIPT.

Slide 11

Slide 11 text

async.map(['file1', 'file2', 'file3'], fs.stat, function(err, results){ // results is now an array of stats for each file }); async.filter(['file1', 'file2', 'file3'], fs.exists, function(results){ // results now equals an array of the existing files });

Slide 12

Slide 12 text

async.parallel([ function(cb) { setTimeout(function() { cb(null, 'one'); }, 1000); }, function(cb) { setTimeout(function() { cb(null, 'two'); }, 2000); } ], function(err, results){ // the results array will equal ['one', 'two'] }); async.series([ function(cb) { fs.exists('file1', cb); }, function(cb) { fs.exists('file2', cb); } ], function(err, results){ // the results array will equal [true, false] });

Slide 13

Slide 13 text

async.waterfall([ function(callback) { callback(null, 'one', 'two'); }, function(arg1, arg2, callback) { // arg1 now equals 'one' and arg2 now equals 'two' callback(null, 'three'); }, function(arg1, callback) { // arg1 now equals 'three' callback(null, 'done'); } ], function (err, result) { // result now equals 'done' });

Slide 14

Slide 14 text

PROMISES (ES6) A PROMISE REPRESENTS THE EVENTUAL RESULT OF AN ASYNCHRONOUS OPERATION.

Slide 15

Slide 15 text

A PROMISE MUST BE IN ONE OF THREE STATES: PENDING, FULFILLED, OR REJECTED.

Slide 16

Slide 16 text

var promise = new Promise(function(resolve, reject) { // do your async stuff resolve("Done!"); }); promise .then(function(result) { // result now equals "Done!" }); promise .then(function(result) { // also here it equals "Done!" });

Slide 17

Slide 17 text

var promise = new Promise(function(resolve, reject) { // do your async stuff reject(new Error("Fail!")); }); promise .then(function(result) { // does not get called }) .catch(function(error) { // this does! });

Slide 18

Slide 18 text

function sleepAndReturn(duration, value) { return new Promise(function(resolve, reject) { setTimeout( function() { resolve(value); }, duration ); }); } sleepAndReturn(1000, "Done!") .then(function(result) { // result now equals "Done!" })

Slide 19

Slide 19 text

PROMISE CHAINING sleepAndReturn(1000, "Done!") .then(function(result1) { return result1 + "!!!!"; }) .then(function(result2) { // result2 now equals "Done!!!!!" });

Slide 20

Slide 20 text

PROMISE CHAINING /2 sleepAndReturn(1000, "Done!") .then(function(result1) { return sleepAndReturn(1000, result1 + "!!!!"); }) .then(function(result2) { // result2 now equals "Done!!!!!" });

Slide 21

Slide 21 text

PROMISE CHAINING /3 sleepAndReturn(1000, "Done!") .then(function(result1) { throw new Error("Fuck.."); }) .then(function(result2) { // ... }) .then(function(result2) { // ... }) .catch(function(error) { console.error(error.message); });

Slide 22

Slide 22 text

FROM THIS... getData(function(a) { getMoreData(a, function(b) { getMoreData(b, function(c) { getMoreData(c, function(d) { getMoreData(d, function(e) { // ... }); }); }); }); });

Slide 23

Slide 23 text

TO THIS! getData() .then(getMoreData) .then(getMoreData) .then(getMoreData) .then(getMoreData) .catch(function(error) { // handle error });

Slide 24

Slide 24 text

RECAP > It is easier to read as in cleaner method signatures > It allows us to attach more than one callback to a single promise > It allows for chaining of promises

Slide 25

Slide 25 text

PROMISE COMPOSITION Promise.all([ sleepAndReturn(1000, "Foo"), sleepAndReturn(2000, "Bar") ]) .then(function(result) { // result now equals ["Foo", "Bar"] });

Slide 26

Slide 26 text

PROMISE COMPOSITION Promise.race([ sleepAndReturn(1000, "Foo"), sleepAndReturn(2000, "Bar") ]) .then(function(result) { // result now equals "Foo" });

Slide 27

Slide 27 text

IT'S STILL QUITE CUMBERSOME TO HANDLE EVEN SIMPLE LOGIC THOUGH... JUST THINK ABOUT MAKING A FOR-LOOP WITH PROMISES...

Slide 28

Slide 28 text

var chunks = ["foo", "bar", "baz"]; var result = chunks.reduce(function(acc, chunk) { return acc + chunk; }, "");

Slide 29

Slide 29 text

var chunks = ["foo", "bar", "baz"]; var promiseChain = chunks.reduce(function(acc, chunk) { return acc.then(function(result) { return result + chunk; }); }, Promise.resolve("")); promiseChain.then(function(result) { console.log(result); });

Slide 30

Slide 30 text

WE CAN OBVIOUSLY CREATE SOME PROMISE-BASED HELPERS... (SIMILAR TO THE ONES FROM ASYNC.JS)

Slide 31

Slide 31 text

BLUEBIRD HELPERS Promise.any Promise.map Promise.reduce Promise.filter Promise.each

Slide 32

Slide 32 text

!

Slide 33

Slide 33 text

GENERATORS (ES6)

Slide 34

Slide 34 text

function makeIterator() { var i = 0; return { next: function() { return i < 3 ? { value: i++, done: false } : { done: true }; } } } var iterator = makeIterator(); console.log(iterator.next().value); // 0 console.log(iterator.next().value); // 1 console.log(iterator.next().value); // 2 console.log(iterator.next().done); // true

Slide 35

Slide 35 text

var someCustomObject = {}; someCustomObject[Symbol.iterator] = makeIterator; for (var i of someCustomObject) { console.log(i); } // 0 // 1 // 2

Slide 36

Slide 36 text

A generator is a special type of function that works as a factory for iterators. A FUNCTION BECOMES A GENERATOR IF IT CONTAINS ONE OR MORE yield EXPRESSIONS AND IF IT USES THE function* SYNTAX.

Slide 37

Slide 37 text

function *makeIterator() { for (var i=0; i<3; i++) { yield i; } }; var iterator = makeIterator(); console.log(iterator.next().value); // 0 console.log(iterator.next().value); // 1 console.log(iterator.next().value); // 2 console.log(iterator.next().done); // true

Slide 38

Slide 38 text

Generators compute their yielded values on demand, which allows them to efficiently represent sequences that are expensive to compute, or even infinite sequences!

Slide 39

Slide 39 text

function *count() { var i = 0; while (true) { yield i++; } }; var iterator = count(); console.log(iterator.next().value); // 0 console.log(iterator.next().value); // 1 console.log(iterator.next().value); // 2 // ...

Slide 40

Slide 40 text

PLOT TWIST YIELD CAN READ VALUES PASSED FROM OUTSIDE! THE NEXT() METHOD ACCEPTS A VALUE WHICH CAN BE USED TO MODIFY THE INTERNAL STATE OF THE GENERATOR. A VALUE PASSED TO NEXT() WILL BE TREATED AS THE RESULT OF THE LAST YIELD EXPRESSION THAT PAUSED THE GENERATOR.

Slide 41

Slide 41 text

function *count() { var i = 0; while (true) { var clear = yield i++; if (clear) { i = 0; } } }; var iterator = count(); console.log(iterator.next().value); // 0 console.log(iterator.next().value); // 1 console.log(iterator.next(true).value); // 0 console.log(iterator.next().value); // 1 console.log(iterator.next().value); // 2 // ...

Slide 42

Slide 42 text

WAIT A MINUTE... INSIDE GENERATORS EXECUTION OF CODE CAN BE PAUSED! THAT IS, EXECUTION RESUMES WHEN THE EXTERNAL WORLD CALLS NEXT() ANOTHER TIME

Slide 43

Slide 43 text

function request(url) { makeAjaxCall(url, function(response){ it.next(response); }); } function *main() { var result1 = yield request("http://some.url.1"); var data = JSON.parse(result1); var result2 = yield request("http://some.url.2?id=" + data.id); var resp = JSON.parse(result2); console.log("The value you asked for: " + resp.value); } var it = main(); it.next(); // get it all started

Slide 44

Slide 44 text

OMFG! ASYNC CODE WITH SYNC-LIKE SYNTAX?! I NEED MOAR MADNESS, PLEASE!!

Slide 45

Slide 45 text

A coroutine is a function, marked by the function* syntax, which can suspend itself anywhere in its execution using the yield keyword.

Slide 46

Slide 46 text

function request(url) { return new Promise(function(resolve, reject) { makeAjaxCall(url, function(err, text) { err ? reject(err) : resolve(text); }); }); }

Slide 47

Slide 47 text

function nirvana(g) { var it = g(), ret; (function iterate(val) { ret = it.next(val); if (!ret.done) { ret.value.then(iterate); } })(); }

Slide 48

Slide 48 text

nirvana(function *(){ var searchTerms = yield Promise.all([ request("http://some.url.1"), request("http://some.url.2"), request("http://some.url.3") ]); var searchResults = yield request( "http://some.url.4?search=" + searchTerms.join("+") ); var resp = JSON.parse(searchResults); console.log("Search results: " + resp.value); });

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

var koa = require('koa'); var route = require('koa-route'); var app = koa(); app.use(route.get('/posts', function *() { var posts = yield fetchAllPosts(); this.body = "There are " + posts.length + "posts in DB!"; })); app.listen(3000);

Slide 51

Slide 51 text

ASYNC/AWAIT (ES7)

Slide 52

Slide 52 text

An async function is a special type of function that works as a factory for promises.

Slide 53

Slide 53 text

async function makePromise() { return "bar"; } var promise = makePromise(); promise.then((value) => { // value equals "bar" });

Slide 54

Slide 54 text

async function makePromise() { throw new Error("Whoops!"); } var promise = makePromise(); promise.catch((error) => { // error.message equals "Whoops!" });

Slide 55

Slide 55 text

function sleep(duration) { return new Promise(function(resolve, reject) { setTimeout(function() { resolve() }, duration); }); } function request(url) { return new Promise(function(resolve, reject) { makeAjaxCall(url, function(err, text) { err ? reject(err) : resolve(text); }); }); }

Slide 56

Slide 56 text

async function sleepAndRequest(duration, url) { try { await sleep(duration); var result = await request(url); return result; } catch(err) { // some promise was rejected! throw err; } }

Slide 57

Slide 57 text

sleepAndRequest(1000, "http://some.url/") .then(...) .catch(...) async anotherAsyncFunction() { // ... return await sleepAndRequest(1000, "http://some.url/"); }

Slide 58

Slide 58 text

NODE.JS > Generators are already available in Node.js since v0.11 > To use async/await you need a transpiler (Babel) BROWSERS > You need to transpile in any case :)

Slide 59

Slide 59 text

THE CHERRY ON THE CAKE HOW THE HELL BABEL CAN GENERATE ES5 CODE ABLE TO REPLICATE THE FEATURES OF GENERATOR/ASYNC FUNCTIONS?!

Slide 60

Slide 60 text

async function foo() { await sleep(100); return await request("http://foo.bar"); } function foo() { return regeneratorRuntime.async(function foo$(context$1$0) { while (1) switch (context$1$0.prev = context$1$0.next) { case 0: context$1$0.next = 2; return regeneratorRuntime.awrap(sleep(100)); case 2: context$1$0.next = 4; return regeneratorRuntime.awrap(request("http://foo.bar")); case 4: return context$1$0.abrupt("return", context$1$0.sent); case 5: case "end": return context$1$0.stop(); } }, null, this); }

Slide 61

Slide 61 text

!

Slide 62

Slide 62 text

That's all I got... ! THANKS FOR LISTENING! ! > Gihtub stefanoverna > Twitter steffoz