{"id":1511,"date":"2016-09-08T18:40:05","date_gmt":"2016-09-08T22:40:05","guid":{"rendered":"http:\/\/codinggorilla.domemtech.com\/?p=1511"},"modified":"2016-09-09T09:32:25","modified_gmt":"2016-09-09T13:32:25","slug":"alternatives-to-deeply-nested-callback-functions-in-javascript","status":"publish","type":"post","link":"http:\/\/165.227.223.229\/index.php\/2016\/09\/08\/alternatives-to-deeply-nested-callback-functions-in-javascript\/","title":{"rendered":"Alternatives to Deeply-Nested Callback Functions in Javascript"},"content":{"rendered":"<p>A few days ago, I wrote a server in <a href=\"https:\/\/nodejs.org\/en\/\" target=\"_blank\">Node.js<\/a>, the purpose of which is to email\u00c2\u00a0me when an API found in Nuget is updated. I thought the project\u00c2\u00a0would take a few\u00c2\u00a0hours, but as it turned out, it took several days. You may ask &#8220;How is this possible for such an easy problem?&#8221; Unfortunately, I spent a lot of time trying to figure out what API to use to read a text file, and how to use the API. It led me to an understanding of a fundamental problem with Javascript known as &#8220;callback hell&#8221; (1, 2).<\/p>\n<p><!--more--><\/p>\n<p>In languages like C# and Java, file system I\/O requests are usually <a href=\"https:\/\/en.wikipedia.org\/wiki\/Callback_(computer_programming)#Design\" target=\"_blank\">blocking<\/a>:\u00c2\u00a0the function does not return until the request is complete. A\u00c2\u00a0call to <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.io.file.readalltext(v=vs.110).aspx\" target=\"_blank\">System.IO.File.ReadAllText<\/a> opens a file, reads all the lines of text in the file into a string, closes the file, and returns the string. Control flow is transferred to the function and does not return until completion. Blocking functions are\u00c2\u00a0easy to use and understand in an <a href=\"https:\/\/en.wikipedia.org\/wiki\/Imperative_programming\" target=\"_blank\">imperative<\/a> or <a href=\"https:\/\/en.wikipedia.org\/wiki\/Functional_programming\" target=\"_blank\">functional<\/a>\u00c2\u00a0programming context.<\/p>\n<p>However, in Javascript, most APIs are non-blocking in order to boost performance and responsiveness of an application. Non-blocking function calls are implemented using a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Callback_(computer_programming)\" target=\"_blank\">callback function<\/a>,\u00c2\u00a0a computation that is executed by another function. For example, fs.readFile is a non-blocking function that opens a file, reads the text in the file, calls a callback function with two\u00c2\u00a0arguments, one of which contains the text, and closes the file. Code that textually follows fs.readFile cannot depend on the data because the callback is invoked asynchronously. Since the data is available\u00c2\u00a0through\u00c2\u00a0the\u00c2\u00a0callback function, a sequence of callback functions invocations is required, one dependent on the result of an enclosing callback. When callbacks are written as\u00c2\u00a0anonymous functions, the dependency is a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Nesting_(computing)\" target=\"_blank\">nesting<\/a>.<\/p>\n<h3>Deeply-nested callback functions<\/h3>\n<p>In my project,\u00c2\u00a0I wanted to create an array of URLs for APIs in Nuget.org from a file. Each URL in the file is on a separate line, and may contain trailing spaces, tabs, new lines, and carriage returns. Using nested callback functions, the Javascript code for this may look like the following:<\/p>\n\n<p>As we implement\u00c2\u00a0the code that further processes the list of URLs (to request the webpage and extract dates of when the API was updated),\u00c2\u00a0the depth of the nesting callback functions increases. Callback chains is an implementation of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Use-define_chain\" target=\"_blank\">a DU-chain<\/a>\u00c2\u00a0of asynchronous variables, which is, unfortunately, the result of the design of Javascript. \u00c2\u00a0At some point\u00c2\u00a0<a href=\"http:\/\/callbackhell.com\/\" target=\"_blank\">the code becomes unmanageable<\/a>\u00c2\u00a0(3).<\/p>\n<h3>Alternatives to deeply-nested callback functions<\/h3>\n<p>Over the years, a number of solutions have been developed to solve deep nesting (4-9).<\/p>\n<h5>Declare a function for each nesting<\/h5>\n<p>Perhaps the easiest solution is to place each block corresponding to the callback in a separate function. The advantage of this that each block is now at the same lexical level.<\/p>\n\n<p>One\u00c2\u00a0must judiciously decide between placing\u00c2\u00a0short blocks into separate functions that may be far removed from the context of the enclosing\/calling block. However, this solution does not really solve the main problem of long chains of callback functions: a function is still a function regardless if it is has a name or is anonymous.<\/p>\n<h5>Function chaining using Promises<\/h5>\n<p><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Promise\" target=\"_blank\">Promises for Javascript<\/a>\u00c2\u00a0is an extension of a callback\u00c2\u00a0(10, 11). Functions that return a Promise can be chained together using the &#8220;then&#8221; method at the same lexical level.<\/p>\n\n<h3>Support for Asynchronous Programming<\/h3>\n<p>Support for asynchronous operations within\u00c2\u00a0the language are available for many languages, including Javascript in ES8\/ES2017. (NB: async\/await was dropped from ES7\/ES2016. See the <a href=\"https:\/\/tc39.github.io\/ecma262\/2016\/\" target=\"_blank\">spec<\/a>.) The async and await keywords\u00c2\u00a0eliminate the need for explicit callback functions. With the await function, continuation is registered as a callback with the awaiting expression. async\/await is a feature of ES8, but\u00c2\u00a0is available in Node.js using <a href=\"https:\/\/babeljs.io\/\" target=\"_blank\">Babel<\/a>. (12-16)<\/p>\n<h5>Await\/Async in ES8\/ES2017<\/h5>\n<p>This solution works with\u00c2\u00a0Node.js 4.6+ and\u00c2\u00a0<a href=\"https:\/\/babeljs.io\/\" target=\"_blank\">Babel<\/a>. To set up Webstorm, <a href=\"http:\/\/codinggorilla.domemtech.com\/?p=1499\" target=\"_blank\">follow these instructions<\/a>.<\/p>\n\n<h5>Asyncawait API<\/h5>\n<p>A similar solution is available for ES6 Javascript using\u00c2\u00a0the API &#8220;asyncawait&#8221;, available through NPM. It provides a similar syntax and works well.<\/p>\n\n<h3>Further Information<\/h3>\n<ol>\n<li>Callback Hell.\u00c2\u00a0<a href=\"http:\/\/callbackhell.com\/\" target=\"_blank\">http:\/\/callbackhell.com\/<\/a><\/li>\n<li>Pyramid of doom (programming).\u00c2\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/Pyramid_of_doom_(programming)\" target=\"_blank\">https:\/\/en.wikipedia.org\/wiki\/Pyramid_of_doom_(programming)<\/a>.<\/li>\n<li>Harrison, Warren, and Curtis Cook. &#8220;Are deeply nested conditionals less readable?.&#8221; <i>Journal of Systems and Software<\/i> 6.4 (1986): 335-341.\u00c2\u00a0<a href=\"http:\/\/www.sciencedirect.com\/science\/article\/pii\/0164121286900038\" target=\"_blank\">http:\/\/www.sciencedirect.com\/science\/article\/pii\/0164121286900038<\/a><\/li>\n<li>Computer Programming\/Coding Style\/Minimize nesting.\u00c2\u00a0<a href=\"https:\/\/en.wikibooks.org\/wiki\/Computer_Programming\/Coding_Style\/Minimize_nesting\" target=\"_blank\">https:\/\/en.wikibooks.org\/wiki\/Computer_Programming\/Coding_Style\/Minimize_nesting<\/a><\/li>\n<li>Handling Synchronous Asynchronous Loops In Javascript\/Node.JS.\u00c2\u00a0<a href=\"https:\/\/zackehh.com\/handling-synchronous-asynchronous-loops-javascriptnode-js\/\" target=\"_blank\">https:\/\/zackehh.com\/handling-synchronous-asynchronous-loops-javascriptnode-js\/<\/a><\/li>\n<li>Green, Thomas R. G. &#8220;Ifs and thens: Is nesting just for the birds?.&#8221; <i>Software: Practice and Experience<\/i> 10.5 (1980): 373-381.\u00c2\u00a0<a href=\"http:\/\/onlinelibrary.wiley.com\/doi\/10.1002\/spe.4380100505\/abstract\" target=\"_blank\">http:\/\/onlinelibrary.wiley.com\/doi\/10.1002\/spe.4380100505\/abstract<\/a><\/li>\n<li>Clarke, Lori A., Jack C. Wileden, and Alexander L. Wolf. &#8220;Nesting in Ada programs is for the birds.&#8221; <i>ACM Sigplan Notices<\/i>. Vol. 15. No. 11. ACM, 1980.<a href=\"http:\/\/dl.acm.org\/citation.cfm?id=948651\" target=\"_blank\"> http:\/\/dl.acm.org\/citation.cfm?id=948651<\/a><\/li>\n<li><a href=\"https:\/\/www.quora.com\/How-do-you-make-an-async-function-synchronous\" target=\"_blank\">https:\/\/www.quora.com\/How-do-you-make-an-async-function-synchronous<\/a><\/li>\n<li><a href=\"http:\/\/stackabuse.com\/avoiding-callback-hell-in-node-js\/\" target=\"_blank\">http:\/\/stackabuse.com\/avoiding-callback-hell-in-node-js\/<\/a><\/li>\n<li>Futures and promises.\u00c2\u00a0<a href=\"https:\/\/en.wikipedia.org\/wiki\/Futures_and_promises\" target=\"_blank\">https:\/\/en.wikipedia.org\/wiki\/Futures_and_promises<\/a><\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Promise\" target=\"_blank\">https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Promise<\/a><\/li>\n<li><a href=\"http:\/\/stackabuse.com\/node-js-async-await-in-es7\/\" target=\"_blank\">http:\/\/stackabuse.com\/node-js-async-await-in-es7\/<\/a><\/li>\n<li><a href=\"http:\/\/es6-features.org\/\" target=\"_blank\">http:\/\/es6-features.org\/<\/a><\/li>\n<li>Bierman, Gavin, et al. &#8220;Pause\u00e2\u20ac\u2122n\u00e2\u20ac\u2122Play: Formalizing Asynchronous C^\\ sharp.&#8221;<i>European Conference on Object-Oriented Programming<\/i>. Springer Berlin Heidelberg, 2012. <a href=\"http:\/\/link.springer.com\/chapter\/10.1007\/978-3-642-31057-7_12\" target=\"_blank\">http:\/\/link.springer.com\/chapter\/10.1007\/978-3-642-31057-7_12<\/a><\/li>\n<li>Tasirlar, Sagnak, and Vivek Sarkar. &#8220;Data-driven tasks and their implementation.&#8221; <i>2011 International Conference on Parallel Processing<\/i>. IEEE, 2011.<a href=\"http:\/\/dl.acm.org\/citation.cfm?id=2066922\" target=\"_blank\"> http:\/\/dl.acm.org\/citation.cfm?id=2066922<\/a><\/li>\n<li>Cordemans, Piet, Eric Steegmans, and Jeroen Boydens. &#8220;Task Parallel Paradigms: a Comparative Case Study.&#8221; <i>Annual Journal of Electronics<\/i>. Vol. 7. Technical Univ. of Sofia, 2013.<a href=\"https:\/\/lirias.kuleuven.be\/handle\/123456789\/416602\" target=\"_blank\"> https:\/\/lirias.kuleuven.be\/handle\/123456789\/416602<\/a><\/li>\n<li>Callback heaven for Node.js with async\/await.\u00c2\u00a0<a href=\"https:\/\/github.com\/yortus\/asyncawait\" target=\"_blank\">https:\/\/github.com\/yortus\/asyncawait<\/a><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A few days ago, I wrote a server in Node.js, the purpose of which is to email\u00c2\u00a0me when an API found in Nuget is updated. I thought the project\u00c2\u00a0would take a few\u00c2\u00a0hours, but as it turned out, it took several days. You may ask &#8220;How is this possible for such an easy problem?&#8221; Unfortunately, I &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/165.227.223.229\/index.php\/2016\/09\/08\/alternatives-to-deeply-nested-callback-functions-in-javascript\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Alternatives to Deeply-Nested Callback Functions in Javascript&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[],"tags":[],"_links":{"self":[{"href":"http:\/\/165.227.223.229\/index.php\/wp-json\/wp\/v2\/posts\/1511"}],"collection":[{"href":"http:\/\/165.227.223.229\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/165.227.223.229\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/165.227.223.229\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/165.227.223.229\/index.php\/wp-json\/wp\/v2\/comments?post=1511"}],"version-history":[{"count":0,"href":"http:\/\/165.227.223.229\/index.php\/wp-json\/wp\/v2\/posts\/1511\/revisions"}],"wp:attachment":[{"href":"http:\/\/165.227.223.229\/index.php\/wp-json\/wp\/v2\/media?parent=1511"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/165.227.223.229\/index.php\/wp-json\/wp\/v2\/categories?post=1511"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/165.227.223.229\/index.php\/wp-json\/wp\/v2\/tags?post=1511"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}