{"id":3086,"date":"2013-12-18T09:39:25","date_gmt":"2013-12-18T15:39:25","guid":{"rendered":"http:\/\/bililite.com\/blog\/?p=3086"},"modified":"2013-12-25T19:14:48","modified_gmt":"2013-12-26T01:14:48","slug":"promises-and-event-handers","status":"publish","type":"post","link":"https:\/\/bililite.com\/blog\/2013\/12\/18\/promises-and-event-handers\/","title":{"rendered":"Promises and Event Handers"},"content":{"rendered":"<p>There's a subtlety in using  <a href=\"http:\/\/bililite.com\/blog\/2013\/12\/17\/promises-api\/\" title=\"Promises API\">Promises<\/a> with event handlers or any code that's executed <a href=\"http:\/\/bililite.com\/blog\/2013\/12\/16\/thinking-about-synchonicity\/\" title=\"Thinking about synchonicity\">asynchronously<\/a>.<\/p>\r\n\r\n<p>Promises are supposed to be used for future values, with the <code class=\"language-javascript\" >reject<\/code> handler acting like an exception handler, so that the Promise constructor actually catches real exceptions and turns them into <code class=\"language-javascript\" >reject<\/code>s (from the<a href=\"https:\/\/github.com\/jakearchibald\/ES6-Promises\/blob\/master\/lib\/promise\/promise.js#L37\"> polyfill<\/a>; I assume the browser-implemented code works similarly):<\/p>\r\n<pre><code class=\"language-javascript\" >try {\r\n  resolver(resolvePromise, rejectPromise);\r\n} catch(e) {\r\n  rejectPromise(e);\r\n}<\/code><\/pre>\r\n\r\n<p>But asynchronous code runs <em>outside<\/em> the execution unit that runs <code class=\"language-javascript\" >resolver()<\/code>, so any exceptions there have to be caught explicitly:<\/p>\r\n<pre><code class=\"language-html\" >&lt;button id=one&gt;Click Me&lt;\/button&gt;\r\n&lt;button id=two&gt;Don't Click Me&lt;\/button&gt;\r\n&lt;script&gt;\r\nvar promise = new Promise(function(resolve, reject){\r\n\tdocument.querySelector('#one').onclick = function(){\r\n\t\tresolve ('You Clicked!');\r\n\t};\r\n\tdocument.querySelector('#two').onclick = function(){\r\n\t\tthrow new Error ('You Clicked!');\r\n\t};\r\n});\r\n\r\npromise.then(function(msg){\r\n\talert('Button clicked: '+msg);\r\n}, function(err){\r\n\talert('Error caught:'+err.message);\r\n});\r\n&lt;\/script&gt;<\/code><\/pre>\r\n<p>Clicking button two gives an uncaught exception error, not the alert from the <code class=\"language-javascript\" >then()<\/code>. You have to catch the exceptions:<\/p>\r\n<pre><code class=\"language-javascript\" >\tdocument.querySelector('#two').onclick = function(){\r\n\t\ttry {\r\n\t\t\tthrow new Error ('You Clicked!');\r\n\t\t} catch (e) {\r\n\t\t\treject(e);\r\n\t\t}\r\n\t};\r\n<\/code><\/pre>\r\n<p>or resolve to a new promise that can catch the error:<\/p>\r\n<pre><code class=\"language-javascript\" >\tdocument.querySelector('#two').onclick = function(){\r\n\t\tresolve(new Promise(function (){\r\n\t\t\tthrow new Error ('You Clicked!');\r\n\t\t}));\r\n\t};\r\n<\/code><\/pre>\r\n\r\n<p>The other subtlety (which is obvious from the definition of a Promise) is that Promises are once-only; in the above code, clicking either button settles the Promise and further clicking does nothing. Event handlers can be called multiple times, so you have to think about what you intend.<\/p>","protected":false},"excerpt":{"rendered":"There's a subtlety in using Promises with event handlers or any code that's executed asynchronously. Promises are supposed to be used for future values, with the reject handler acting like an exception handler, so that the Promise constructor actually catches real exceptions and turns them into rejects (from the polyfill; I assume the browser-implemented code [&hellip;]","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[],"_links":{"self":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/3086"}],"collection":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/comments?post=3086"}],"version-history":[{"count":8,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/3086\/revisions"}],"predecessor-version":[{"id":3104,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/3086\/revisions\/3104"}],"wp:attachment":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/media?parent=3086"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/categories?post=3086"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/tags?post=3086"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}