{"id":343,"date":"2013-09-20T11:37:28","date_gmt":"2013-09-20T01:37:28","guid":{"rendered":"https:\/\/mindbleach.com\/words\/?p=343"},"modified":"2013-09-20T12:11:48","modified_gmt":"2013-09-20T02:11:48","slug":"self-replacing-promises","status":"publish","type":"post","link":"https:\/\/mindbleach.com\/words\/2013\/09\/20\/self-replacing-promises\/","title":{"rendered":"Javascript: Self-replacing Promises"},"content":{"rendered":"<p>My application has several resources that need to be loaded just once, and used often afterwards.<\/p>\n<p>Here is a pattern that I&#8217;m finding quite useful lately:<\/p>\n<pre class=\"brush: javascript; gutter: true\">\/** \r\n * Retrieve the resource once only.\r\n * If the resource hasn&#039;t been loaded yet, \r\n *   return a deferred that resolves to the resource.\r\n * If the resource has been loaded, \r\n *   return the resource directly.\r\n *\/ \r\nApp.getResource = function() {\r\n  \/\/Return the resource or the deferred if it&#039;s set already\r\n  if (App._resource) \r\n    return App._resource; \r\n  \/\/Otherwise build, set and return a deferred that \r\n  \/\/replaces itself when it&#039;s finished loading\r\n  else\r\n    return App._resource = $.getJSON(&quot;resource\/url&quot;).then(\r\n      function(data) {\r\n        console.debug(&quot;Loaded resource&quot;);\r\n        return App._resource = data;\r\n      }\r\n    );\r\n};<\/pre>\n<ul>\n<li>The first time the function is called, it fetches the resource and returns a deferred object.<\/li>\n<li>When the promise resolves, it passes the resource to handlers.<\/li>\n<li>If called again before the promise resolves, it returns the same promise. (won&#8217;t fetch twice)<\/li>\n<li>After the promise has resolved, the function instead returns the resource directly.<\/li>\n<li>If the resource can&#8217;t be loaded, the promise fails instead, and is not replaced.<\/li>\n<\/ul>\n<hr \/>\n<p>To use directly;<\/p>\n<pre class=\"brush: javascript; gutter: true\">$.when(App.getResource()).done(function(resource) {\r\n  \/\/Use the parameter from the promise\r\n  resource.doStuff();\r\n});<\/pre>\n<p>The $.when call transparently converts a non-promise into a resolved promise with that value. The snippet behaves the same whether App.getResource() has been previously loaded or not.<\/p>\n<hr \/>\n<p>So why replace the promise at all? Sometimes you need to be able to treat the resource like a synchronous value, such as within a library or a function that is called synchronously.<\/p>\n<pre class=\"brush: javascript; gutter: true\">\/\/Here&#039;s a class with a synchronously-called function\r\nvar Model = Backbone.Model.extend({\r\n  ...\r\n  validate: function(attrs) {\r\n    if (App.getResource().exists(attrs[id])) {\r\n      return &quot;Model with that id already exists&quot;;\r\n    } else {\r\n      return null;\r\n    }\r\n  }\r\n});\r\nvar model = new Model();\r\n\r\n\/\/Wait for everything necessary to load first.\r\n$.when(App.getResource(), model.fetch(), ...).done(\r\n  function() {\r\n    if (model.isValid()) doFoo();\r\n    else doBar();\r\n  });<\/pre>\n<p>This code waits for App.getResource() to resolve, as well as for any other needed promises.\u00a0Afterwards, App.getResource() can just be treated like a synchronous function.<\/p>\n<hr \/>\n<p>This pattern enables flexible and transparent use of remote resources, in both synchronous and asynchronous ways.<\/p>\n<p>The App.getResource() function is also quite similar to a <strong>Lazy Promise<\/strong>, as discussed by <a href=\"http:\/\/blog.jcoglan.com\/2013\/03\/30\/callbacks-are-imperative-promises-are-functional-nodes-biggest-missed-opportunity\/\" target=\"_blank\">James Coglan<\/a>.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>My application has several resources that need to be loaded just once, and used often afterwards. Here is a pattern that I&#8217;m finding quite useful lately: \/** * Retrieve the resource once only. * If the resource hasn&#039;t been loaded &hellip; <a href=\"https:\/\/mindbleach.com\/words\/2013\/09\/20\/self-replacing-promises\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24,11],"tags":[59,17,58,57,60],"class_list":["post-343","post","type-post","status-publish","format-standard","hentry","category-javascript-programming","category-programming","tag-asynchronous","tag-javascript","tag-jquery","tag-promise","tag-resolving"],"_links":{"self":[{"href":"https:\/\/mindbleach.com\/words\/wp-json\/wp\/v2\/posts\/343"}],"collection":[{"href":"https:\/\/mindbleach.com\/words\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mindbleach.com\/words\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mindbleach.com\/words\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mindbleach.com\/words\/wp-json\/wp\/v2\/comments?post=343"}],"version-history":[{"count":4,"href":"https:\/\/mindbleach.com\/words\/wp-json\/wp\/v2\/posts\/343\/revisions"}],"predecessor-version":[{"id":345,"href":"https:\/\/mindbleach.com\/words\/wp-json\/wp\/v2\/posts\/343\/revisions\/345"}],"wp:attachment":[{"href":"https:\/\/mindbleach.com\/words\/wp-json\/wp\/v2\/media?parent=343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mindbleach.com\/words\/wp-json\/wp\/v2\/categories?post=343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mindbleach.com\/words\/wp-json\/wp\/v2\/tags?post=343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}