{"id":125,"date":"2015-08-18T23:32:51","date_gmt":"2015-08-18T21:32:51","guid":{"rendered":"http:\/\/www.hacksrus.net\/blog\/?p=125"},"modified":"2015-08-19T08:57:18","modified_gmt":"2015-08-19T06:57:18","slug":"a-solution-to-swallowed-exceptions-in-es6s-promises","status":"publish","type":"post","link":"https:\/\/www.hacksrus.net\/blog\/2015\/08\/a-solution-to-swallowed-exceptions-in-es6s-promises\/","title":{"rendered":"A Solution To Swallowed Exceptions In ES6&#8217;s Promises"},"content":{"rendered":"<p>You have probably heard about ES6&#8217;s built-in <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Promise\" target=\"_blank\">Promises<\/a> and how they can provide a <a href=\"https:\/\/strongloop.com\/strongblog\/node-js-callback-hell-promises-generators\/\" target=\"_blank\">way out of JavaScript&#8217;s callback hell<\/a>.<\/p>\n<p>While the intend and purpose for Promises is clear very quickly, getting used to them is not as straightforward and the devil lies in the detail.<\/p>\n<p>One thing that bit us quite late during a recent refactoring and has caused a lot of frustration was the fact that <strong>Promises &#8220;swallow&#8221; exceptions by default<\/strong>.<\/p>\n<p>This does include exceptions such as <em>ReferenceError\u00a0<\/em>so that the following code runs perfectly fine, without ever letting you know that something went wrong:<\/p>\n<pre lang=\"javascript\">var myPromise = Promise.resolve();\r\n\r\nmyPromise\r\n  .then(function() {\r\n    console.log(\"Step 1\");\r\n  })\r\n  .then(function() {\r\n    console.log(\"Step 2\", thisNameDoesNotExist);\r\n  });\r\n<\/pre>\n<p>What happens here is that the implementation of Promise wraps our function (the <em>onFulfillment<\/em> handler as it is called in the language specification) in a try-catch block. <strong>Instead of throwing the error<\/strong> and causing our interpreter to crash (but print a convenient error message at least), it catches it and marks the promise <em>p<\/em> as <strong>rejected<\/strong>.<\/p>\n<p>Those of you who have worked with Promises before will say that you need an <em>onRejection<\/em> handler function of course, and you are perfectly right:<\/p>\n<pre lang=\"javascript\">var myPromise = Promise.resolve();\r\n\r\nmyPromise\r\n  .then(function() {\r\n    console.log(\"Step 1\");\r\n  })\r\n  .then(function() {\r\n    console.log(\"Step 2\", thisNameDoesNotExist);\r\n  }, function(e) {\r\n    console.log(\"Promise rejected, error:\", e);\r\n  });\r\n<\/pre>\n<p>However, this still doesn&#8217;t work. What is wrong here? In order to catch errors in the <strong>last<\/strong> actual <em>onFulfillment<\/em> handler in our chain, we need to <strong>add another step<\/strong> where nothing but the error catching happens. We could use another <em>.then()<\/em> with an empty function as its first argument, but a more elegant way is to use <em>.catch()<\/em> which takes only the <em>onRejection<\/em> handler for its arguments:<\/p>\n<pre lang=\"javascript\">var myPromise = Promise.resolve();\r\n\r\nmyPromise\r\n  .then(function() {\r\n    console.log(\"Step 1\");\r\n  })\r\n  .then(function() {\r\n    console.log(\"Step 2\", thisNameDoesNotExist);\r\n  })\r\n  .catch(function(e) {\r\n    console.log(\"Promise rejected, error:\", e);\r\n  });\r\n<\/pre>\n<p>Much better, that will do. In theory. In reality though, it is very easy to forget to specify the .catch() handler at the end, have it in the wrong place etc.<br \/>\nBelieve me, that will happen, no matter how careful you are. And if it&#8217;s not you who forgets it, it will be some guy on your team.<\/p>\n<p>For that reason, <a href=\"https:\/\/github.com\/petkaantonov\/bluebird\">Bluebird<\/a>, one of the most popular Promise\u00a0libraries, has a <strong>&#8220;default&#8221; onRejection handler<\/strong> which will <strong>print all errors from rejected Promises\u00a0to stderr<\/strong>. This is a huge improvement and while it can still result in unexpected behaviour because it doesn&#8217;t interrupt execution, it at least gives a hint where things are dodgy.<\/p>\n<p>While that is all well and good, we didn&#8217;t feel like using a library, now that we finally got native support for Promises from io.js. And as it turns out, you don&#8217;t have to. Because just as there is\u00a0<em>process.on(&#8216;unhandledException&#8217;, ..)<\/em>, since its 1.4.1 release, io.js also has\u00a0the <strong><em><a href=\"https:\/\/iojs.org\/api\/process.html#process_event_unhandledrejection\" target=\"_blank\">unhandledRejection<\/a><\/em><\/strong> event, which is very similar to Bluebird&#8217;s default handler, except that you have to<strong> specify it yourself<\/strong>:<\/p>\n<pre lang=\"javascript\">var myPromise = Promise.resolve();\r\n\r\nprocess.on('unhandledRejection', function(error, promise) {\r\n  console.error(\"UNHANDLED REJECTION\", error.stack);\r\n});\r\n\r\nmyPromise\r\n  .then(function() {\r\n    console.log(\"Step 1\");\r\n  })\r\n  .then(function() {\r\n    console.log(\"Step 2\", thisNameDoesNotExist);\r\n  });\r\n<\/pre>\n<p>Do this once in your project and you will never have Promises swallow your exceptions again. Happy debugging!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You have probably heard about ES6&#8217;s built-in Promises and how they can provide a way out of JavaScript&#8217;s callback hell. While the intend and purpose for Promises is clear very quickly, getting used to them is not as straightforward and the devil lies in the detail. One thing that bit us quite late during a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-125","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"https:\/\/www.hacksrus.net\/blog\/wp-json\/wp\/v2\/posts\/125","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.hacksrus.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hacksrus.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hacksrus.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hacksrus.net\/blog\/wp-json\/wp\/v2\/comments?post=125"}],"version-history":[{"count":10,"href":"https:\/\/www.hacksrus.net\/blog\/wp-json\/wp\/v2\/posts\/125\/revisions"}],"predecessor-version":[{"id":135,"href":"https:\/\/www.hacksrus.net\/blog\/wp-json\/wp\/v2\/posts\/125\/revisions\/135"}],"wp:attachment":[{"href":"https:\/\/www.hacksrus.net\/blog\/wp-json\/wp\/v2\/media?parent=125"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hacksrus.net\/blog\/wp-json\/wp\/v2\/categories?post=125"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hacksrus.net\/blog\/wp-json\/wp\/v2\/tags?post=125"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}