1 / 43

Avoiding Callback Hell with Async.js

Avoiding Callback Hell with Async.js. www.codehenge.net. C. Aaron Cois, Ph.D. Sup. www.codehenge.net. @ aaroncois. github.com / cacois. So, JavaScript?. What’s cool?. Robust event model Asynchronous programming Client-side and Server-side. What’s cool?. Robust event model

fiona
Télécharger la présentation

Avoiding Callback Hell with Async.js

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Avoiding Callback Hell with Async.js www.codehenge.net C. Aaron Cois, Ph.D.

  2. Sup www.codehenge.net @aaroncois github.com/cacois

  3. So, JavaScript?

  4. What’s cool? • Robust event model • Asynchronous programming • Client-side and Server-side

  5. What’s cool? • Robust event model • Asynchronous programming • Client-side and Server-side

  6. What can cause headaches?

  7. Callbacks JavaScript uses callback functions to handle asynchronous control flow

  8. Anatomy of a Callback fs= require('fs'); fs.readFile('f1.txt','utf8',function(err,data){ if(err){ returnconsole.log(err); } console.log(data); });

  9. Anatomy of a Callback fs= require('fs'); fs.readFile('f1.txt','utf8',function(err,data){ if(err){ returnconsole.log(err); } console.log(data); }); Anonymous, inline callback

  10. Anatomy of a Callback fs= require('fs'); fs.readFile('f1.txt','utf8', function(err,data){ if(err){ returnconsole.log(err); } console.log(data); } ); Equivalent formatting

  11. Callback Hell When working with callbacks, nesting can get quite out of hand…

  12. Callback Hell func1(param,function(err,res){ func2(param,function(err, res){ func3(param,function(err, res){ func4(param,function(err, res){ func5(param,function(err, res){ func6(param,function(err, res){ func7(param,function(err, res){ func8(param,function(err, res){ func9(param,function(err, res){ // Do something… }); }); }); }); }); }); }); }); });

  13. Callback Hell func1(param,function(err,res){ func2(param,function(err, res){ func3(param,function(err, res){ func4(param,function(err, res){ func5(param,function(err, res){ func6(param,function(err, res){ func7(param,function(err, res){ func8(param,function(err, res){ func9(param,function(err, res){ // Do something… }); }); }); }); }); }); }); }); });

  14. Best case, this is linear func1 func2 func3 . . . func9

  15. But it can branch func1 func2 func2 func3 func3 func3 func3 . . . . . . . . . . . . func9 func9 func9 func9

  16. But it can branch func1 … func2(param,function(err, results){ _.each(results, func3(param,function(err, res){ func4(param,function(err, res){ … }); } }); }); func2 func2 func3 func3 func3 func3 . . . . . . . . . . . . func9 func9 func9 func9

  17. Some specific challenges • When branching, we can’t know the order of these function calls • If we want parallel execution, we have to do some real gymnastics to get return data back together • Also, scoping becomes a challenge

  18. A more ‘real’ example vardb= require('somedatabaseprovider'); //get recent posts http.get('/recentposts',function(req, res){ // open database connection db.openConnection('host',creds,function(err, conn){ res.param['posts'].forEach(post){ conn.query('select * from users where id='+post['user'],function(err,users){ conn.close(); res.send(users[0]); }); } }); });

  19. A more ‘real’ example vardb= require('somedatabaseprovider'); //get recent posts http.get('/recentposts',function(req, res){ // open database connection db.openConnection('host',creds,function(err, conn){ res.param['posts'].forEach(post){ conn.query('select * from users where id='+post['user'],function(err,users){ conn.close(); res.send(users[0]); }); } }); });

  20. Solutions • You can make this easier to read by separating anonymous functions • Passing function references instead of anonymous functions helps even more

  21. Inline callback fs= require('fs'); fs.readFile('f1.txt','utf8',function(err,data){ if(err){ returnconsole.log(err); } console.log(data); });

  22. Separate Callback fs= require('fs'); callback = function(err,data){ if(err){ returnconsole.log(err); } console.log(data); } fs.readFile('f1.txt','utf8',callback);

  23. Can turn this: vardb= require('somedatabaseprovider'); http.get('/recentposts',function(req,res){ db.openConnection('host', creds, function(err, conn){ res.param['posts'].forEach(post){ conn.query('select * from users where id='+ post['user'],function(err,results){ conn.close(); res.send(results[0]); }); } }); });

  24. …into this vardb= require('somedatabaseprovider'); http.get('/recentposts',afterRecentPosts); functionafterRecentPosts(req, res){ db.openConnection('host',creds,function(err, conn){ afterDBConnected(res, conn); }); } functionafterDBConnected(err, conn){ res.param['posts'].forEach(post){ conn.query('select * from users where id='+post['user'],afterQuery); } } functionafterQuery(err, results){ conn.close(); res.send(results[0]); }

  25. Good start! • Callback function separation is a nice aesthetic fix • The code is more readable, and thus more maintainable • But it doesn’t improve your control flow • Branching and parallel execution are still problems

  26. Enter Async.js Async.jsprovides common patterns for asyncronouscode control flow https://github.com/caolan/async BONUS: Also provides some common functional programming paradigms

  27. Client or Server -side My examples will mostly be Node.js code, but Async.js can be used in both client and server side code

  28. Serial/Parallel Execution Run functions in series… …or parallel Function 1 Function 2 Function 3 Function 4 Function 1 Function 2 Function 3 Function 4

  29. Serial/Parallel Functions async.parallel([ function(){ ... }, function(){ ... } ], callback); async.series([ function(){ ... }, function(){ ... } ]);

  30. Serial/Parallel Functions async.parallel([ function(){ ... }, function(){ ... } ], callback); async.series([ function(){ ... }, function(){ ... } ]); Single Callback!

  31. Waterfall Execution Async also provides a flow for serial execution, passing results to successive functions args args args Function 1 Function 2 Function 3 Function 4

  32. Waterfall async.waterfall([ function(){ callback(arg1); }, function(arg1) { callback(ar2,ar3) }, function(arg1, arg2){ callback(“done”) } ],function(err, results){ // results now equals “done” });

  33. Times Times() offers a shortcut to iterating over a function multiple times in parallel async.times(5, function(n, next) { createUser(n,function(err, user { next(err, user); }) }, function(err, users){ // ‘users’ now contains 5 users });

  34. Let’s see some code…

  35. Collection Management Functional programming provides some useful tools that are becoming mainstream Specifically, map, reduce, and filter operations are now common in many languages

  36. Map The Map operation calls a given function on each item of a list

  37. Map async.map([‘file1’,‘file2’,‘file3’], funct, callback); async.mapSeries([‘file1’,‘file2’], funct, callback); async.mapLimit([‘file1’,‘file2’,‘file3’], limit, funct, callback);

  38. Reduce The Reduce operation aggregates a list of values into a single result, using a specified aggregation function

  39. Reduce Initial result state async.reduce([val1,val2,…],memo, function(memo,item,cb){ // doStuff }); async.reduceRight([val1,val2],memo, function(memo,item,cb){ // doStuff });

  40. Filter To minimize computational overhead, it’s often helpful to filter data sets to only operate on acceptable values Async.js provides a Filter function to do just this

  41. Filter async.filter([‘file1’,‘file2’,‘file3’], fs.exists, function(results){ // results is now an array // of files that exist });

  42. In Summation Async.js provides: • Powerful asynchronous control flows • Functional programming tools Write clean code, live the dream.

  43. Thanks! Any questions? @aaroncois

More Related