Callbacks, promises, generators - asynchronous javascript

13,989 views

Published on

How to manage asynchronous functions.

Published in: Engineering, Technology, Business
3 Comments
32 Likes
Statistics
Notes
  • What about Fibers as an abstraction to make code look synchronous but still keeping the efficiency of asynchronous code?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • That's right but still it's not defined in the spec thus there is no guarantee it's implemented consistently.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Q.all is not specific to Q, there is Promise.all which does the same thing
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
13,989
On SlideShare
0
From Embeds
0
Number of Embeds
187
Actions
Shares
0
Downloads
149
Comments
3
Likes
32
Embeds 0
No embeds

No notes for slide

Callbacks, promises, generators - asynchronous javascript

  1. 1. Callbacks, Promises, Generators Łukasz Kużyński @wookiebpl
  2. 2. callbacks, promises, generators Asynchronous code ! var result = asyncFunction(); // you won't get result immediately typeof result === 'undefined'; // true
  3. 3. callbacks, promises, generators Callbacks asyncFunction(function() { // i’ll be called when the execution ends ! // where is the result? // there was any error? });
  4. 4. 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 });
  5. 5. 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? });
  6. 6. callbacks, promises, generators Callbacks - Own patterns - DON’t do it
  7. 7. callbacks, promises, generators Callbacks - Callback-based function
  8. 8. callbacks, promises, generators Callbacks - Asynchronous patterns
  9. 9. 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 });
  10. 10. callbacks, promises, generators Callbacks - Callback hell
  11. 11. 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) { // ... }); }); }); }); };
  12. 12. 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
  13. 13. callbacks, promises, generators Callbacks - Callback hell - map
  14. 14. callbacks, promises, generators Callbacks - Callback hell
  15. 15. callbacks, promises, generators Callbacks - Introducing async ASYNC by Caolan McMahon „Higher-order functions and common patterns for asynchronous code”
  16. 16. 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 });
  17. 17. 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; });
  18. 18. 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] });
  19. 19. callbacks, promises, generators Callbacks - async
  20. 20. callbacks, promises, generators Callbacks - asynC Collections each, map, filter, reduce, some ... Control flow series, parallel, waterfall, compose ...
  21. 21. 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
  22. 22. callbacks, promises, generators Promises var promise = promisedFunction(); ! typeof promise !== 'undefined'; // true 'then' in promise; // true
  23. 23. callbacks, promises, generators Promises - introducing Q Q by Kris Kowal „A tool for making and composing asynchronous promises in JavaScript”
  24. 24. 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 };
  25. 25. 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); // ...
  26. 26. 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?
  27. 27. callbacks, promises, generators Promises - fulfilling by promise
  28. 28. 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'} });
  29. 29. 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
  30. 30. 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.
  31. 31. 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.”
  32. 32. callbacks, promises, generators Promises AND NPM packages Always expose your package API as callback-based functions! It’s a standard
  33. 33. callbacks, promises, generators Generators
  34. 34. 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 }
  35. 35. callbacks, promises, generators Generators - ES6 feature
  36. 36. 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); });
  37. 37. callbacks, promises, generators Generators + Exceptions var 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); });
  38. 38. callbacks, promises, generators Generators
  39. 39. callbacks, promises, generators Generators - introducing CO CO by TJ Holowaychuk „The ultimate generator based flow-control goodness for nodejs (supports thunks, promises, etc)”
  40. 40. 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; })();
  41. 41. 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'); })();
  42. 42. 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) { });
  43. 43. 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 ] })();
  44. 44. callbacks, promises, generators Generators - co
  45. 45. callbacks, promises, generators Generators - NOT YET! Supported by firefox and chrome (disabled by default) Node.js 0.11.* - not stable yet
  46. 46. 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
  47. 47. 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
  48. 48. callbacks, promises, generators Q&A Questions?
  49. 49. callbacks, promises, generators Font „Blue Highway” from http://typodermicfonts.com/ Thanks!

×