{"id":652,"date":"2011-01-05T05:42:34","date_gmt":"2011-01-05T13:42:34","guid":{"rendered":"http:\/\/www.visophyte.org\/blog\/?p=652"},"modified":"2011-01-05T05:42:34","modified_gmt":"2011-01-05T13:42:34","slug":"visualizing-asynchronous-javascript-promises-q-style-promisesb","status":"publish","type":"post","link":"https:\/\/www.visophyte.org\/blog\/2011\/01\/05\/visualizing-asynchronous-javascript-promises-q-style-promisesb\/","title":{"rendered":"Visualizing asynchronous JavaScript promises (Q-style Promises\/B)"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-653\" title=\"jstut-promise-vis-popups-js-parse-failure\" src=\"http:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/01\/jstut-promise-vis-popups-js-parse-failure.png\" alt=\"\" width=\"596\" height=\"275\" srcset=\"https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/01\/jstut-promise-vis-popups-js-parse-failure.png 596w, https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/01\/jstut-promise-vis-popups-js-parse-failure-300x138.png 300w\" sizes=\"auto, (max-width: 596px) 100vw, 596px\" \/><\/p>\n<p>Asynchronous JS can be unwieldy and confusing. \u00a0Specifically, callbacks can be unwieldy, especially when you introduce error handling and start chaining asynchronous operations. \u00a0So, people frequently turn to something like Python&#8217;s <a href=\"http:\/\/twistedmatrix.com\/\">Twisted<\/a>&#8216;s <a href=\"http:\/\/twistedmatrix.com\/documents\/current\/core\/howto\/defer.html\">deferreds<\/a> which provide for explicit error handling and the ability for &#8216;callbacks&#8217; to return yet another asynchronous operation.<\/p>\n<p>In <a href=\"http:\/\/www.commonjs.org\/\">CommonJS<\/a>-land, there are <a href=\"http:\/\/wiki.commonjs.org\/wiki\/Promises\">proposals<\/a> for deferred-ish promises. \u00a0In a dangerously concise nutshell, these are:<\/p>\n<ul>\n<li><a href=\"http:\/\/wiki.commonjs.org\/wiki\/Promises\/A\">Promises\/A<\/a>: promises have a <strong>then<\/strong>(<em>callback<\/em>, <em>errback<\/em>) method.<\/li>\n<li><a href=\"http:\/\/wiki.commonjs.org\/wiki\/Promises\/B\">Promises\/B<\/a>: the promises module has a <strong>when<\/strong>(<em>value<\/em>, <em>callback<\/em>, <em>errback<\/em>) helper function.<\/li>\n<\/ul>\n<p>I am in the Promises\/B camp because the <strong>when<\/strong> construct lets you not care whether <em>value<\/em> is actually a promise or not both now and in the future. \u00a0The bad news about Promises\/B is that:<\/p>\n<ul>\n<li>It is currently not duck typable (but there is a <a href=\"http:\/\/groups.google.com\/group\/commonjs\/browse_thread\/thread\/f3b39c1a242b4cc6\">mailing list proposal<\/a> to support unification that I am all for) and so really only works if you have exactly one promises module in your application.<\/li>\n<li>The implementation will make your brain implode-then-explode because it is architected for safety and to support transparent remoting.<\/li>\n<\/ul>\n<p>To elaborate on the (elegant) complexity, it uses a message-passing idiom where you send your &#8220;when&#8221; request to the promise which is then responsible for actually executing your callback or error back. \u00a0So if <em>value<\/em> is actually a value, it just invokes your callback on the value. \u00a0If <em>value<\/em> was a promise, it queues your callback until the promise is resolved. \u00a0If <em>value<\/em> was a rejection, it invokes your rejection handler. \u00a0When a callback returns a new promise, any &#8220;when&#8221;s that were targeted at the associated promise end up retargeted to the newly returned promise. \u00a0The bad debugging news is that almost every message-transmission step is forward()ed into a subsequent turn of the event loop which results in debuggers losing a lot of context. \u00a0(Although anything that maintains linkages between the code that created a timer and the fired timer event or other causal chaining at least has a fighting chance.)<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-654\" title=\"jstut-promise-vis-popups-success\" src=\"http:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/01\/jstut-promise-vis-popups-success.png\" alt=\"\" width=\"600\" height=\"429\" srcset=\"https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/01\/jstut-promise-vis-popups-success.png 600w, https:\/\/www.visophyte.org\/blog\/wp-content\/uploads\/2011\/01\/jstut-promise-vis-popups-success-300x214.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>In short, promises make things more manageable, but they don&#8217;t really make things less confusing, at least not without a little help. \u00a0Some time ago I created a modified version of <a href=\"https:\/\/github.com\/kriskowal\">Kris Kowal<\/a>&#8216;s <a href=\"https:\/\/github.com\/kriskowal\/q\">Q<\/a> library implementation that:<\/p>\n<ul>\n<li>Allows you to describe what a promise actually represents using human words.<\/li>\n<li>Tracks relationships between promises (or allows you to describe them) so that you can know all of the promises that a given promise depends\/depended on.<\/li>\n<li>Completely abandons the security\/safety stuff that kept promises isolated.<\/li>\n<\/ul>\n<p>The end goal was to support debugging\/understanding of code that uses promises by converting that data into something usable like a visualization. \u00a0I&#8217;ve done this now, applying it to jstut&#8217;s (soon-to-be-formerly narscribblus&#8217;) load process to help understand what work is actually being done. \u00a0If you are somehow using jstut trunk, you can invoke <em>document.jstutVisualizeDocLoad(\/* show boring? *\/ false)<\/em> from your JS console and see such a graph in all its majesty for your currently loaded document.<\/p>\n<p>The first screenshot (show boring = true) is of a case where a parse failure of the root document occurred and we display a friendly parse error screen. \u00a0The second screenshot (show boring = false) is the top bit of the successful presentation of the same document where I have not arbitrarily deleted a syntactically important line.<\/p>\n<p>A basic description of the visualization:<\/p>\n<ul>\n<li>It&#8217;s a hierarchical <a href=\"http:\/\/vis.stanford.edu\/protovis\/\">protovis<\/a> <a href=\"http:\/\/vis.stanford.edu\/protovis\/ex\/indent.html\">indented tree<\/a>. \u00a0The children of a node are the promises it depended on. \u00a0A promise that depended in parallel(-ish) on multiple promises will have multiple children. \u00a0The special case is that if we had a &#8220;when&#8221; W depending on promise X, and X was resolved with promise Y, then W gets retargeted to Y. \u00a0This is represented in the visualization as W having children X and Y, but with Y having a triangle icon instead of a circle in order to differentiate from W having depended on X and Y in parallel from the get-go.<\/li>\n<li>The poor man&#8217;s timeline on the right-hand side shows the time-span between when the promise was created and when it was resolved. \u00a0It is not showing how long the callback function took to run, although it will fall strictly within the shown time-span. \u00a0Time-bar widths are lower bounded at 1 pixel, so the duration of something 1-pixel wide is not representative of anything other than position.<\/li>\n<li>Nodes are green if they were resolved, yellow if they were never resolved, red if they were rejected. \u00a0Nodes are gray if the node and its dependencies were already shown elsewhere in the graph; dependencies are not shown in such a case. \u00a0This reduces redundancy in the visualization while still expressing actual dependencies.<\/li>\n<li>Timelines are green if the promise was resolved, maroon if it was never resolved or rejected. \u00a0If the timeline is never resolved, it goes all the way to the right edge.<\/li>\n<li>Boring nodes are elided when so configured; their interesting children spliced in in their place. \u00a0A node is boring if its &#8220;what&#8221; description starts with &#8220;auto:&#8221; or &#8220;boring:&#8221;. \u00a0The when() logic automatically annotates an &#8220;auto:functionName&#8221; if the callback function has a name.<\/li>\n<\/ul>\n<p>You can find <a href=\"http:\/\/hg.mozilla.org\/users\/bugmail_asutherland.org\/narscribblus\/file\/1f851cef80be\/lib\/narscribblus\/utils\/pwomise.js\">pwomise.js<\/a> and <a href=\"http:\/\/hg.mozilla.org\/users\/bugmail_asutherland.org\/narscribblus\/file\/1f851cef80be\/lib\/narscribblus\/utils\/pwomise-vis.js\">pwomise-vis.js<\/a> in the narscribblus\/jstut repo. \u00a0It&#8217;s called pwomise not to be adorable but rather to make it clear that it&#8217;s not promise.js. \u00a0I have added various comments to pwomise.js that may aid in understanding. \u00a0Sometime soon I will update my demo setup on clicky.visophyte.org so that all can partake.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Asynchronous JS can be unwieldy and confusing. \u00a0Specifically, callbacks can be unwieldy, especially when you introduce error handling and start chaining asynchronous operations. \u00a0So, people frequently turn to something like Python&#8217;s Twisted&#8216;s deferreds which provide for explicit error handling and &hellip; <a href=\"https:\/\/www.visophyte.org\/blog\/2011\/01\/05\/visualizing-asynchronous-javascript-promises-q-style-promisesb\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[7,8,4],"tags":[98,99,89,97,56],"class_list":["post-652","post","type-post","status-publish","format-standard","hentry","category-debugging","category-program-execution","category-visualizing","tag-asynchronous","tag-jstut","tag-narscribblus","tag-promises","tag-protovis"],"_links":{"self":[{"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/posts\/652","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/comments?post=652"}],"version-history":[{"count":9,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/posts\/652\/revisions"}],"predecessor-version":[{"id":663,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/posts\/652\/revisions\/663"}],"wp:attachment":[{"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/media?parent=652"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/categories?post=652"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.visophyte.org\/blog\/wp-json\/wp\/v2\/tags?post=652"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}