Top Banner
Callbacks, Promises, Generators Łukasz Kużyński @wookiebpl
49

Callbacks, promises, generators - asynchronous javascript

Aug 19, 2014

Download

Engineering

How to manage asynchronous functions.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Callbacks, promises, generators - asynchronous javascript

Callbacks, Promises, GeneratorsŁukasz Kużyński @wookiebpl

Page 2: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Asynchronous code

!var result = asyncFunction(); // you won't get result immediately typeof result === 'undefined'; // true

Page 3: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks

asyncFunction(function() { // i’ll be called when the execution ends ! // where is the result? // there was any error?

});

Page 4: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Node.js way - callback-based functions

var asyncFunction = function(args, ..., callback) { setTimeout(function() { ! // "returning" result callback(null, {tasty: 'sandwich'}); ! // or // "throwing" errors callback(new Error('Error message')); }, 50); }; !asyncFunction(function(error, result, result1 ...) { if (error) { // handle error return; // don't forget about this! } // handle result });

Page 5: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Own patterns - DON’t do it

var asyncFunction = function(callback) { setTimeout(function() { callback({tasty: 'sandwich'}); }, 50); }; !asyncFunction(function(result) { result; // {tasty: 'sandwich'} ! // but... what about errors? });

Page 6: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Own patterns - DON’t do it

Page 7: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Callback-based function

Page 8: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Asynchronous patterns

Page 9: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Callback hell

var fetchResultFromDb = function(callback) { db.fetch(function(error, result) { if (error) { callback(error); return; } ! serializeResult(result, function(error, result) { if (error) { callback(error); return; } callback(null, result); // finally! }); }); }; !fetchResultFromDb(function(error, result) { if (error) { console.error(error); return; } ! result; // end result });

Page 10: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Callback hell

Page 11: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Callback hell

var function1 = function (callback) { function2(function(error, result) { if (error) { callback(error); return; } ! function3(result, function(error, result) { if (error) { callback(error); return; } ! function4(result, function(error, result) { if (error) { callback(error); return; } ! function5(result, function(error, result) { // ... }); }); }); }); };

Page 12: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Callback hell - map -var map = function(input, callback) { var results = [], handleIterationResult = function(error, result) { if (error) { callback(error); return; } results.push(result); if (results.length === input.length) { callback(null, results); } }; input.forEach(function(num) { sum(num, handleIterationResult); }); }; !var sum = function(num, callback) { callback(null, num + num); }; !map([1, 2, 3, 4, 5], function(error, result) { if (error) { console.error(error); return; }; result; // [2, 4, 6, 8, 10] });

DON’t do it

Page 13: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Callback hell - map

Page 14: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Callback hell

Page 15: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - Introducing async

ASYNCby Caolan McMahon

„Higher-order functions and common patterns for asynchronous code”

Page 16: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - async waterfall

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

Page 17: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - async waterfall

var fetchResultFromDb = function(callback) { async.waterfall([ db.fetch.bind(db), // to preserve function context serializeResult ], callback); }; !fetchResultFromDb(function(error, result) { if (error) { console.error(error); return; } result; });

Page 18: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - async MAP

var sum = function(num, callback) { callback(null, num + num); }; !async.map([1, 2, 3, 4, 5], sum, function(error, result) { if (error) { console.error(error); return; } result; // [2, 4, 6, 8, 10] });

Page 19: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - async

Page 20: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Callbacks - asynC

Collectionseach, map, filter, reduce, some ...

Control flowseries, parallel, waterfall, compose ...

Page 21: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises

According to Promises/A+ specification„promise is an object or function with a then method whose behavior conforms to this specification (...) [and] represents the eventual result of an asynchronous operation„

More specs http://wiki.commonjs.org/wiki/Promises

Page 22: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises

var promise = promisedFunction(); !typeof promise !== 'undefined'; // true 'then' in promise; // true

Page 23: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises - introducing Q

Qby Kris Kowal

„A tool for making and composing asynchronous promises in JavaScript”

Page 24: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises - Promise-based function

var promisedFunction = function() { var defer = Q.defer(); ! setTimeout(function() { ! // REJECTING // "throwing" error defer.reject(new Error('Error message')); ! // or // FULFILLING // "returning" result - defer.resolve({tasty: 'sandwich'}); ! }, 50); ! return defer.promise; // remember to always return a promise };

Page 25: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises - basic usage

!var promise = promisedFunction(); !promise.then(function(result) { // handle result }, function(error) { // handle error }); !// more "listeners" promise.then(onSuccess, onError); // ...

Page 26: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises - fulfilling by promise

Q.fcall(function() { var defer = Q.defer(); setTimeout(function() { defer.resolve(['tasty']); }, 50); return defer.promise; }) .then(function(result) { var defer = Q.defer(); setTimeout(function() { defer.resolve(result.concat(['sandwich'])); }, 50); return defer.promise; }) .then(function(result) { result; // ['tasty', 'sandwich'] }, function(error) { // handling error });

Remember waterfall pattern from async library?

Page 27: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises - fulfilling by promise

Page 28: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises - COnverting callback-based functions

var callbackBasedFunction = function(callback) { setTimeout(function() { callback(null, {tasty: 'sandwich'}); }, 50); }; !var promiseBasedFunction = Q.denodeify(callbackBasedFunction); !promiseBasedFunction() .then(function(result) { result; // {tasty: 'sandwich'} });

Page 29: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises - previous waterfall example

var fetchFromDb = function() { return Q.ninvoke(db, 'fetch') .then(Q.denodeify(serializeResults)); }; !fetchFromDb() .then(function(result) {

result; });

You have to convert each callback-based function into promise-based for chaining

Page 30: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises - MAP

var promisedSum = Q.denodeify(sum); !var promises = [1, 2, 3, 4, 5].map(function(num) { return promisedSum(num); }); !Q.all(promises).then(function(result) { console.log(result); });

Q.all is a custom Q library function. Not in spec.

Page 31: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises - compatibility

https://github.com/kriskowal/q#the-middle

„When working with promises provided by other libraries, you should convert it to a Q promise. Not all promise libraries make the same guarantees as Q and certainly don’t provide all of the same methods.”

Page 32: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Promises AND NPM packages

Always expose your package API as callback-based functions!

It’s a standard

Page 33: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators

Page 34: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators - ES6 feature

var generatorFunction = function*() { // note asterisk var value = yield 1; // waits here for „next” call value; // {tasty: 'sandwich' } yield 2; }; !var gen = generatorFunction(); gen.next(); // { value: 1, done: false } gen.next({tasty: 'sandwich'}); // { value: 2, done: false } gen.next(); // { value: undefined, done: true }

Page 35: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators - ES6 feature

Page 36: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators + promise

var promisedStep = Q.denodeify(function(callback) { setTimeout(function() { callback(null, {tasty: 'sandwich'}); }, 50); }); !var generatorFunction = function*() { var result = yield promisedStep; result; // {tasty: 'sandwich'} }; !var gen = generatorFunction(); var result = gen.next(); result.value() .then(function(result) { gen.next(result); }, function(error) { gen.throw(error); });

Page 37: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators + Exceptionsvar promisedStep = Q.denodeify(function(callback) { setTimeout(function() { callback(new Error('No butter!')); }, 50); }); !var generatorFunction = function*() { try { var result = yield promisedStep; } catch (error) { error; // [Error: No butter!] } }; !var gen = generatorFunction(); !var result = gen.next(); result.value() .then(function(result) { gen.next(result); }, function(error) { gen.throw(error); });

Page 38: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators

Page 39: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators - introducing CO

COby TJ Holowaychuk

„The ultimate generator based flow-control goodness for nodejs (supports thunks, promises, etc)”

Page 40: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators - CO

var fetchResultFromDb = function*() { var records = yield thunkify(db.fetch.bind(db))(); return yield thunkify(serializeResults)(records); }; !co(function*() { var result = yield fetchResultFromDb; })();

Page 41: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators - THUNK

var asyncFunction = function(arg1, arg2, calback) { setTimeout(function() { callback(null, {tasty: 'sandwich with '+arg1+' and '+arg2}) }, 50); }; co(function*() { yield asyncFunction; // what about arguments? yield asyncFunction.bind(undefined, 'butter', 'cheese'); })();

Page 42: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators - THUNK

var thunkifiedAsyncFunction = thunkify(asyncFunction); // fn(args, ..., callback) asyncFunction('butter', 'cheese', function(err, result) { }); !// transformed into // fn(args)(callback) thunkifiedAsyncFunction('butter', 'cheese')(function(err, result) { });

Page 43: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators - co - map

var thunkifiedSum = thunkify(sum); co(function*() { var result = yield [1, 2, 3, 4, 5].map(function(num) { return thunkifiedSum(num); }); ! result; // [ 2, 4, 6, 8, 10 ] })();

Page 44: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators - co

Page 45: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Generators - NOT YET!

Supported by firefox and chrome (disabled by default)

Node.js 0.11.* - not stable yet

Page 46: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

CONCLUSIONs

You need a library for asynchronous code

Use callback-based functions for public API

Pick solution that is fine for you and your team

Page 47: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

More informations

Promises/A+ Performance Hits You Should Be Aware Of

https://github.com/substack/node-seq

http://wiki.commonjs.org/wiki/Promises

Page 48: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Q&A

Questions?

Page 49: Callbacks, promises, generators - asynchronous javascript

callbacks, promises, generators

Font „Blue Highway” from http://typodermicfonts.com/

Thanks!