<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: craig martin</title>
    <description>The latest articles on Forem by craig martin (@craigmichaelmartin).</description>
    <link>https://forem.com/craigmichaelmartin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F125756%2F533dd89b-1588-4f96-ae3a-e5ebcc8cca56.jpg</url>
      <title>Forem: craig martin</title>
      <link>https://forem.com/craigmichaelmartin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/craigmichaelmartin"/>
    <language>en</language>
    <item>
      <title>A High Level Introduction to Machine Learning</title>
      <dc:creator>craig martin</dc:creator>
      <pubDate>Mon, 16 Dec 2019 14:12:10 +0000</pubDate>
      <link>https://forem.com/craigmichaelmartin/a-high-level-introduction-to-machine-learning-310m</link>
      <guid>https://forem.com/craigmichaelmartin/a-high-level-introduction-to-machine-learning-310m</guid>
      <description>&lt;p&gt;The goal of this article is to explain at a high level &lt;em&gt;the concept&lt;/em&gt; of machine learning. We'll say nothing about implementation details.&lt;/p&gt;

&lt;p&gt;Lets say my name is Tom, and I start a car insurance company with 50 customers. We'll pretend this number is normal for car insurance companies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Year 1
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A Simple Average Across the Board&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I charge all 50 customers an average amount. Things are going well. We lose a customer every once in a while. But that's normal. We gain one, too, every once in a while. However, over the course of the year we're becoming less and less profitable!&lt;/p&gt;

&lt;p&gt;I look at the data and realize that our best customers (the ones that very rarely get into accidents) are the ones that are leaving, and the customers that are staying (and our new ones) are bad customers (ones that get into accidents alot!) Yikes! Other insurance companies must have some rubric for recognizing good customers, and be luring away our good customers with a better-than-average price.&lt;/p&gt;

&lt;h2&gt;
  
  
  Year 2
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Introducing My Pre-Conceived Stereotypes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I gather all the information we know about our customers (age, type of car, city) and make a chart.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Age&lt;/th&gt;
&lt;th&gt;Car Type&lt;/th&gt;
&lt;th&gt;City&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;2008 Honda Civic&lt;/td&gt;
&lt;td&gt;Nashville&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;td&gt;2018 Toyota Prius&lt;/td&gt;
&lt;td&gt;Brentwood&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;2001 Ford Torus&lt;/td&gt;
&lt;td&gt;Coopertown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I think to myself: young drivers and older drivers are probably more likely to get into accidents; people living in cities probably are more likely too. And I change our prices accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Year 3
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Single-purpose Input Data and Result-based Human Learning&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Things have actually gotten worse. Most surprisingly, this was driven by two "bad" customers leaving, and two "good" customers joining.&lt;/p&gt;

&lt;p&gt;I realize my conception about drivers is not accurate, and it's costing me. I realize I must use actual results data (accidents) to derive my conception of a good/bad customers. However, even my inputs have implicit connotations. I make a new chart with fine-tuned inputs conveying exactly one thing (no secret (secondary) connotations), and add the result data as the final column.&lt;/p&gt;

&lt;p&gt;Here is my new table I'll use to inform my learning:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Driver Age&lt;/th&gt;
&lt;th&gt;Car Age&lt;/th&gt;
&lt;th&gt;Car Self Stop&lt;/th&gt;
&lt;th&gt;Car Blindspot Detection&lt;/th&gt;
&lt;th&gt;City Density (population per sq mile)&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Number of Accidents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;80,000&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;20,000&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;10,000&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Using result data, I can start to see trends: car safety features matter a lot, age is a mixed bag, city density seems to matter... I adjust prices accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Year 4
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Getting Better Data for my Human Learning&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Things have started to get better! Every few months I look at the data again (with updated results / new drivers) and immensely enjoy looking for the thread that connects good drivers vs bad drivers. To my frustration, though, I keep bumping up against a limit - insufficient data. Not results data, but input data. I'll be finding a nice thread, only to see it disappear for some reason that isn't on my chart. Age for example. There are cases where it is the only factor to explain higher percentages of accidents, but there are other cases where it seems to be a non-factor. I am missing some other data input that would account for this. Maybe old age is a factor but only for those driving at night a lot.. I am obsessed with finding the thread, and learn about hardware customers can put in their car so that I can gather data about their actual driving behavior! I immediately offer 10% for drivers who install it.&lt;/p&gt;

&lt;p&gt;A month later I get the first data dump, and it is like Christmas morning!! I have average data into: speed, acceleration from stop, deceleration to stop, music level, percentage of times blinker applied when turning, percentage of time driving with headlights on.&lt;/p&gt;

&lt;p&gt;I add these attributes to my data:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Driver Age&lt;/th&gt;
&lt;th&gt;Car Age&lt;/th&gt;
&lt;th&gt;Car Self Stop&lt;/th&gt;
&lt;th&gt;Car Blindspot Detection&lt;/th&gt;
&lt;th&gt;City Density (population per sq mile)&lt;/th&gt;
&lt;th&gt;Avg. Speed&lt;/th&gt;
&lt;th&gt;Avg. Accel&lt;/th&gt;
&lt;th&gt;Avg. Decel&lt;/th&gt;
&lt;th&gt;Avg. Music Level&lt;/th&gt;
&lt;th&gt;Pct. Blinker When Turning&lt;/th&gt;
&lt;th&gt;Pct. Headlights&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Number of Accidents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;80,000&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;1.4&lt;/td&gt;
&lt;td&gt;1.2&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;88&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;65&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;20,000&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;.8&lt;/td&gt;
&lt;td&gt;1.9&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;92&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;10,000&lt;/td&gt;
&lt;td&gt;55&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;97&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Wow! I spend days and days in my office trying to find the thread... elderly who drive at night a lot and decelerate quickly, young who have loud music and don't use their blinkers when turning... these make sense in my mind (perhaps vision problems and distraction, respectively). But it bothers me that while it is a very strong indicator, there are notable exceptions for each case. Using the previous data, there was a weak indication with many outliers. Now it is a stronger indication (75%!), and with less outliers, but it feels like I'm missing a third or even fourth or fifth factor for each of these cases!&lt;/p&gt;

&lt;h2&gt;
  
  
  Year 5
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The Crossroads&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My company is doing great again, even with a model that is not as accurate as I want it to be. But I find myself at a cross-roads. I've learned of two paths I could go down.&lt;/p&gt;

&lt;p&gt;The first approach would be to create a feedback mechanism into the car hardware. Based on the learnings from my data, I can have the hardware "beep" at the driver to indicate they are in a bad situation. For example, the young driver can have loud music (23%), or occasionally miss applying a blinker (31%), but if both (75%) it crosses my chosen 70% threshold, and will beep. It seems like this would help drivers be safer, and turn bad drivers into good ones! This would help our company!&lt;/p&gt;

&lt;p&gt;The second approach is to apply Machine Learning to the data. With machine learning, an algorithm would look at the data inputs and result (accidents) and &lt;em&gt;itself&lt;/em&gt; decide what inputs (by themselves, but more likely coupled with any number of other inputs) are factors. I read that whereas humans have a difficult time finding deeply-nested related factors, machines can do this easily. The tradeoff of this approach, is that I no longer know which inputs are the ones which result in the projected output - and even if I did, it might be so intertwined and nuanced (maybe even touching every input under different circumstance) - that I can not have the hardware "beep" at the driver: it'd be far too nuanced for a human to backward derive from a simple "beep".&lt;/p&gt;

&lt;p&gt;I've seen so much promise with my Human Learning model, that I decide to go the second path and see if a machine can push it further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Year 6
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Machine Learning&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I spend some time "normalizing" my inputs for machine learning. I already have each input expressing only one thing, but now need to adjust all values to be values between 0 and 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const normalize = (val, min, max) =&amp;gt; (val - min) / (max - min);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I assume a min/max based on the data I have, not theoretical. (EG, min age is 25, max is 65). For any new data I get, everything is recomputed anyway.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Driver Age&lt;/th&gt;
&lt;th&gt;Car Age&lt;/th&gt;
&lt;th&gt;Car Self Stop&lt;/th&gt;
&lt;th&gt;Car Blindspot Detection&lt;/th&gt;
&lt;th&gt;City Density (population per sq mile)&lt;/th&gt;
&lt;th&gt;Avg. Speed&lt;/th&gt;
&lt;th&gt;Avg. Accel&lt;/th&gt;
&lt;th&gt;Avg. Decel&lt;/th&gt;
&lt;th&gt;Avg. Music Level&lt;/th&gt;
&lt;th&gt;Pct. Blinker When Turning&lt;/th&gt;
&lt;th&gt;Pct. Headlights&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Number of Accidents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;.6&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;.2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;.7&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;.1&lt;/td&gt;
&lt;td&gt;.7&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;.4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.5&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;.3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;.2&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I am curious how the machine does! So, like before, I omit one record at random, perform the learning (machine instead of my own), and check the one omitted record. The record has an accident, and the machine correctly projects it! I do this over and over, and find that it has a 92% correct projection! Not just under a favorite situation (my "old age" logic accounting for elderly drivers at night was 85% - but that was my cherry-picked best scenario!) but as an average across &lt;em&gt;any&lt;/em&gt; driver data.&lt;/p&gt;

&lt;p&gt;I am incredulous, and spend the year changing my business model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Year 6
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Use Machine Learning to Upset the Market&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I create hardware similar to the data-gathering hardware I used before, but which transmits the data in real time to our servers. Customers pay based on their real time risk. There is no 6 month plans or contracts of any type. We don't run any background information or offer any pre-set pricing. You incur cost as you drive, commensurate with your real-time driving behavior.&lt;/p&gt;

&lt;p&gt;By year end, we upset the coverage industry and have almost half the market. The following year we eat the whole pie.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflections from the Caymans
&lt;/h2&gt;

&lt;p&gt;As I sip a Mojito, retired on a beach, I think back through my years.&lt;/p&gt;

&lt;p&gt;My first year neglected that patterns exist: I charged every driver the same.&lt;/p&gt;

&lt;p&gt;The next few years I struggled to identify the patterns.&lt;/p&gt;

&lt;p&gt;The final years I realized the futility of the human mind to maintain large number of interconnected factors (A if a lot of B and no C, coupled with D if alot of A otherwise E, negated if F, always disregarding the popular G as a red herring, etc, etc). Human minds cannot handle many factors; machines can; and so I had machines making these decisions.&lt;/p&gt;

&lt;p&gt;I think to myself how cruel the human condition: receiving an overload of inputs in life, and not having the mechanism to correctly understand the true patterns. How thousands of years of history have seen humans erecting systems of understandings based on low-hanging fruit, not deep and nuanced learnings, that unfairly classifies and discriminates - that mistakes the important issues (and solutions) for popular red herrings. How stereotypes exist as the reduction of the true number of factors constituting a realty.&lt;/p&gt;

&lt;p&gt;But what do I know, I'm just a car insurance guy drunk on a beach.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>introduction</category>
      <category>example</category>
    </item>
    <item>
      <title>Hooks for those who know React</title>
      <dc:creator>craig martin</dc:creator>
      <pubDate>Tue, 12 Nov 2019 15:01:43 +0000</pubDate>
      <link>https://forem.com/craigmichaelmartin/hooks-for-those-who-know-react-3n89</link>
      <guid>https://forem.com/craigmichaelmartin/hooks-for-those-who-know-react-3n89</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XBITPXnb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wzfu86ai3m8084zbnyq8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XBITPXnb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wzfu86ai3m8084zbnyq8.png" alt='React Hooks are not a new concept: they are "just react"'&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hooks are not a new concept in React - they are a re-implementation (a new API) for state and side effects in React that better aligns with two existing concepts in react: the concept of Components as the primitive model for UIs, and of these components being declarative.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A95_lIty--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/n011sjaf7hj2qh9nmaoy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A95_lIty--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/n011sjaf7hj2qh9nmaoy.png" alt="Declarative Code and Component UI Primitives are two essential concepts of React"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's look at the concept of Components as the UI Primitives first. Before hooks, Components are a mental idea that don't map directly to either of the two existing implementations: the class-based or function-based. While the mental model was right, the implementation was forced. And so you’d have to sometimes switch between them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v_s4G_aj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/27tmuvsx4ocgqj7wluzj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v_s4G_aj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/27tmuvsx4ocgqj7wluzj.png" alt="Before Hooks, switching between component implementations was common"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What’s going on is there is a missing primitive for components: a single Component implementation which is like stateful functions with effects - and that is what hooks enable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jR0OAYsN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/sc7l29f38zotpa1gest7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jR0OAYsN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/sc7l29f38zotpa1gest7.png" alt="Before Hooks, there is a missing primitive for components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before looking at how Hooks solves for this, let’s look at the other concept hooks are better aligned with: Using declarative code to make components easier to reason about.&lt;/p&gt;

&lt;p&gt;React components have always allowed declarative code to be mapped to an imperative DOM. In the case of functional components, this declarative approach included not just the render, but the whole component (b/c the whole component was just a render): a mapping of data to an object describing the UI. React would take this object and surgically (imperatively) update the DOM.&lt;/p&gt;

&lt;p&gt;However, if a component needed local state or side-effects - it had to be implemented as a class components. And while the render function was still declarative, the class instance itself (where the state lived and side-effects were managed) was mutable. State and side-effects were tied to a mutating instance, which made them harder to reason about.&lt;/p&gt;

&lt;p&gt;The react team wanted the single missing component primitive to itself be declarative (as functional components were), even when it included state and side-effects.&lt;/p&gt;

&lt;p&gt;Hooks provide for this missing component primitive. They allow components to be truly declarative even if they contain state and side-effects. They are a re-conception and re-implemenation of state and side-effects in React - an implementation instead of in class components, is in functional components making use of "hooks".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--slv5MNtQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/dw3jpsg14cgem81jj60j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--slv5MNtQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/dw3jpsg14cgem81jj60j.png" alt="Hooks make components declarative even if they contain state or side-effects"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  "Ok, Yeah, cool, whatever.. So what &lt;em&gt;are&lt;/em&gt; hooks?"
&lt;/h3&gt;

&lt;p&gt;Hooks are functions used with functional components that let you "hook into" React state and perform side-effects (as previously done with lifecycle hooks).&lt;/p&gt;

&lt;p&gt;React provides built-in Hooks, and these can even be used to build more advanced custom hooks.&lt;/p&gt;

&lt;p&gt;By convention hook functions are prefixed with “use”.&lt;/p&gt;

&lt;p&gt;While hooks are “just functions”, they are not your father’s functions... They do not behave like normal functions. We'll come back to that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r4SASJk---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/welfy21lumriprkyw8so.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r4SASJk---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/welfy21lumriprkyw8so.jpg" alt="Hooks do not behave like normal functions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;useState&lt;/code&gt; hook for managing local state
&lt;/h3&gt;

&lt;p&gt;Rather than the state living on a mutable &lt;code&gt;this&lt;/code&gt; instance of the component (&lt;code&gt;this.state&lt;/code&gt; and &lt;code&gt;this.setState&lt;/code&gt;), state is declaratively retrieved from the &lt;code&gt;useState&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;State is now retrieved and set declaratively without mutating the structure of the component (ie as the class instance would be).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q5vWyKdb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ra1e4wtu1phaoj994hgz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q5vWyKdb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ra1e4wtu1phaoj994hgz.png" alt="Rather than the state living on a mutable `this` instance of the component, state is declaratively retrieved from the hook"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The highlighted line shows the &lt;code&gt;useState&lt;/code&gt; hook. The value passed is the initial value. The hook returns an array for two items, state and a setter for that state, and we destructure them to variables count and setCount.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;useEffect&lt;/code&gt; hook for managing side-effects
&lt;/h3&gt;

&lt;p&gt;Rather than side-effects being aligned with the component's mutation (&lt;code&gt;componentDidMount&lt;/code&gt;, &lt;code&gt;componentDidUpdate&lt;/code&gt;, &lt;code&gt;componentWillUnmount&lt;/code&gt;), they are now declaratively aligned with state using the &lt;code&gt;useEffect&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; orients the side effect (and it’s clean-up) with the state, rather than component’s mutation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7neMDi4i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wewpj2vdazzv398jf79b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7neMDi4i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wewpj2vdazzv398jf79b.png" alt="Rather than side-effects being aligned with the component's mutation, they are declaratively aligned with state using the hook"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The highlighted line shows the &lt;code&gt;useEffect&lt;/code&gt; hook. We pass in a function that performs some side-effect, and the state that that effect is coupled with. Whenever that state changes, the effect function is run.&lt;/p&gt;

&lt;h3&gt;
  
  
  "But hold on.. WTF.. wouldn't these hooks be reset every render?"
&lt;/h3&gt;

&lt;p&gt;"The hooks are created &lt;em&gt;inside&lt;/em&gt; the functional component which are called for every render. Looking back up at the &lt;code&gt;useState&lt;/code&gt; example, wouldn't &lt;code&gt;const [count, setCount] = useState(0);&lt;/code&gt; be called every render and keep reseting the count to the initial value of 0?"&lt;/p&gt;

&lt;p&gt;It would seem that way, if &lt;code&gt;useState&lt;/code&gt; was a typical function - but it's not. Hooks are impure* functions - but that impurity is an implementation detail in React that is abstracted away from userland code.&lt;br&gt;
*They are impure as a consequence of JS being the host language, which does not support Algebraic Effects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UozJjWKL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8oxknpfzjdnct8lro89k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UozJjWKL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8oxknpfzjdnct8lro89k.png" alt="Hooks are not typical functions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  An example using hooks
&lt;/h3&gt;

&lt;p&gt;Here is a contrived example using the &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; hooks, vs using class components and lifecycle methods.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G00f8KNJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8kt6btrmwqpa1mnffzi9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G00f8KNJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8kt6btrmwqpa1mnffzi9.png" alt="Example of functional components with hooks, vs class components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is live code of the hooks version (on the left): &lt;a href="https://codesandbox.io/s/greeting-hooks-2uwdg"&gt;https://codesandbox.io/s/greeting-hooks-2uwdg&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is live code of the class component version (on the right):&lt;br&gt;
&lt;a href="https://codesandbox.io/s/greeting-classes-7bmql"&gt;https://codesandbox.io/s/greeting-classes-7bmql&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how in the hook version, state and effects are kept together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NOmFECjr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bqk4xi68eidx7jmwq6ca.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NOmFECjr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bqk4xi68eidx7jmwq6ca.png" alt="Example showing the code groupings of functional components with hooks, vs class components"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A second example using hooks
&lt;/h3&gt;

&lt;p&gt;Lets look at a second example of using hooks. Here are two versions of a contrived component which lets you search for a user, and edit their name.&lt;/p&gt;

&lt;p&gt;Here is the hooks version: &lt;a href="https://codesandbox.io/s/react-hooks-are-a-better-mental-model-f9kql"&gt;https://codesandbox.io/s/react-hooks-are-a-better-mental-model-f9kql&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the class version: &lt;a href="https://codesandbox.io/s/react-classes-are-the-wrong-mental-model-n9zbs"&gt;https://codesandbox.io/s/react-classes-are-the-wrong-mental-model-n9zbs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how, again, the state and effects are kept together with hooks - but more-so this time that a bug is avoided which is in the class component version. ("Save" a user, and while it is saving change the users name. The confirmation message will confirm the wrong name - the newly updated one rather than the one which was saved. This is because by the time the save side-effect finishes, the state is mutated. With hooks, state is functionally-scoped and closed-over, and each render introduces new immutable state.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Hooks add the missing primitive for state/effect sharing.
&lt;/h3&gt;

&lt;p&gt;Now that we've got a grasp on hooks - how functional components using hooks are a new UI primitive which make state and side-effects easier to reasonable through a declarative API - there is one more important note: beyond just co-locating the state and side-effects, these can be abstracted out into a custom re-useable hook. &lt;strong&gt;Hooks represent a primitive for state/effect sharing, as Components are a primitive for UI sharing.&lt;/strong&gt; Building custom Hooks allow for extracting component logic into reusable functions.&lt;/p&gt;

&lt;p&gt;Looking back at our first example. We can build a custom &lt;code&gt;useWidth&lt;/code&gt; hook that extracts the width state and effect. Then that hook can be re-used by any component!&lt;/p&gt;

&lt;p&gt;Here is live code showing the above: &lt;a href="https://codesandbox.io/s/greeting-hooks-as-a-primative-xb0o0"&gt;https://codesandbox.io/s/greeting-hooks-as-a-primative-xb0o0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first glance, it may look like this code-sharing could have been achieved by making a &lt;code&gt;Width&lt;/code&gt; component. But that gets at the heart of it: we don't want a re-useable UI primitive, we want a re-useable state/effect primitive. If it were a UI primitive, the state and effects would be tied to a UI representation - we just want the data, so it can be presented however different components decide.&lt;/p&gt;

&lt;h3&gt;
  
  
  What other built-in Hooks are there?
&lt;/h3&gt;

&lt;p&gt;Basic Hooks&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;useState&lt;/li&gt;
&lt;li&gt;useEffect&lt;/li&gt;
&lt;li&gt;useContext&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additional Hooks&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;useReducer&lt;/li&gt;
&lt;li&gt;useCallback&lt;/li&gt;
&lt;li&gt;useMemo&lt;/li&gt;
&lt;li&gt;useRef&lt;/li&gt;
&lt;li&gt;useImperativeHandle&lt;/li&gt;
&lt;li&gt;useLayoutEffect&lt;/li&gt;
&lt;li&gt;useDebugValue&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  More resources
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://reactjs.org/docs/hooks-intro.html"&gt;Introducing Hooks (reactjs.org)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889"&gt;Making Sense of React Hooks (medium.com)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://overreacted.io/a-complete-guide-to-useeffect/"&gt;A Complete Guide to useEffect (overreacted.io)&lt;/a&gt;&lt;br&gt;
&lt;a href="https://wattenberger.com/blog/react-hooks"&gt;Thinking in React Hooks (wattenberger.com)&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Individual Photos of Class vs Hooks code with and without Highlighting
&lt;/h3&gt;

&lt;p&gt;Classes: &lt;a href="https://thepracticaldev.s3.amazonaws.com/i/9t0sa5bfzos9nh8yfumy.png"&gt;https://thepracticaldev.s3.amazonaws.com/i/9t0sa5bfzos9nh8yfumy.png&lt;/a&gt;&lt;br&gt;
Classes Highlighted: &lt;a href="https://thepracticaldev.s3.amazonaws.com/i/ah9b8plpz32jejub7nfl.png"&gt;https://thepracticaldev.s3.amazonaws.com/i/ah9b8plpz32jejub7nfl.png&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hooks: &lt;a href="https://thepracticaldev.s3.amazonaws.com/i/gupc51cvr005gnkuzriu.png"&gt;https://thepracticaldev.s3.amazonaws.com/i/gupc51cvr005gnkuzriu.png&lt;/a&gt;&lt;br&gt;
Hooks Highlighted: &lt;a href="https://thepracticaldev.s3.amazonaws.com/i/p0tr7pzokmlovbm1v3bw.png"&gt;https://thepracticaldev.s3.amazonaws.com/i/p0tr7pzokmlovbm1v3bw.png&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Together:&lt;br&gt;
&lt;a href="https://thepracticaldev.s3.amazonaws.com/i/8kt6btrmwqpa1mnffzi9.png"&gt;https://thepracticaldev.s3.amazonaws.com/i/8kt6btrmwqpa1mnffzi9.png&lt;/a&gt;&lt;br&gt;
Together Highlighted:&lt;br&gt;
&lt;a href="https://thepracticaldev.s3.amazonaws.com/i/bqk4xi68eidx7jmwq6ca.png"&gt;https://thepracticaldev.s3.amazonaws.com/i/bqk4xi68eidx7jmwq6ca.png&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>hooks</category>
      <category>components</category>
    </item>
    <item>
      <title>React Hooks are a More Accurate Implementation of the React Mental Model</title>
      <dc:creator>craig martin</dc:creator>
      <pubDate>Thu, 26 Sep 2019 03:29:56 +0000</pubDate>
      <link>https://forem.com/craigmichaelmartin/react-hooks-are-a-more-accurate-implementation-of-the-react-mental-model-1k49</link>
      <guid>https://forem.com/craigmichaelmartin/react-hooks-are-a-more-accurate-implementation-of-the-react-mental-model-1k49</guid>
      <description>&lt;p&gt;&lt;em&gt;React Functional Components using Hooks are a More Accurate Implementation of the React Mental Model for State and Effects, than React Classes&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR React made updating the DOM declarative. Hooks made components themselves declarative.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The key of React was allowing declarative code to be mapped to an imperative DOM.&lt;/p&gt;

&lt;p&gt;This was especially true of functional components, which would simply map data to an object describing the UI. React would take this object and surgically (imperatively) update the DOM.&lt;/p&gt;

&lt;p&gt;However, with class components, while the render function was still declarative, the class instance itself (where the state lived) is mutable - which made it harder to reason about.&lt;/p&gt;

&lt;p&gt;The implementation for state and side-effects were within these class components - tied to the mutating instance.&lt;/p&gt;

&lt;p&gt;React hooks are a re-conception and re-implemenation of state and side-effects in React - an implementation instead of in class components, is in functional components. As a basic definition they are functions that let you "hook into" React state and lifecycle features. But the key is their implementation with functional components in a declarative api.&lt;/p&gt;

&lt;p&gt;"But why is this a 'more accurate implementation of the react mental model'?"&lt;/p&gt;

&lt;p&gt;React hooks allow components to be truly declarative even if they contain state and side-effects.&lt;/p&gt;

&lt;p&gt;State is now retrieved declaratively without mutating the structure of the component (ie as the class instance would be).&lt;/p&gt;

&lt;p&gt;Side-effects are now declaratively aligned with state, instead of with the component's mutation.&lt;/p&gt;

&lt;p&gt;Just as the first key of react was a declarative mapper to the DOM, hooks are the second key: providing a declarative api in the component for state and side effects.&lt;/p&gt;

&lt;p&gt;"Um, OK, sure.. How about some code?"&lt;/p&gt;

&lt;p&gt;Lets look at two versions of doing the same thing. The first version uses the initial class-based implementation of state and effects, and second uses the new hook-based implementation.&lt;/p&gt;

&lt;p&gt;The example is an (very contrived) User component. An input will search for the user and display their name, which can be edited and saved.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using React's initial class-based implementation of state and effects
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/react-classes-are-the-wrong-mental-model-n9zbs"&gt;https://codesandbox.io/s/react-classes-are-the-wrong-mental-model-n9zbs&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 * A code sample to show how React class components are
 * not the best implementation of the react mental model.
 *
 * Limitations:
 * - 1. With react classes, `this` is mutable and harder
 *      to reason about
 * - 2. With react classes, the lifecyle hooks are aligned
 *      with the component instead of the data.
 *
 * To see 1: save a user's name, and then immediately
 * change it again. You'll see the confirmation alert has
 * the wrong name (the new one, not the one which was saved).
 * Because "this" is mutated before the save finishes,
 * the wrong data is surfaced to the user.
 *
 * To see 2: Notice how the code for componentDidUpdate
 * and componentDidMount is doing the same thing? What we
 * care about is changes to "username" data but instead
 * the model here is built around changes to the component.
 */&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;handleUsernameChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;handleNameChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;name&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Pretend save that takes two seconds&lt;/span&gt;
    &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User's name has been saved to "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="mi"&gt;2000&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`https://api.github.com/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;componentDidUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prevProps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;prevState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;prevState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;componentWillUnmount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// clean up any lingering promises&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
        Search
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Github Username"&lt;/span&gt;
          &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleUsernameChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;hr&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
              &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
              &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleNameChange&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Here is the live code running. You can see point 1 described in the code comment above: save a user's name, and then immediately change it again. You'll see the confirmation alert has the wrong name (the new one, not the one which was saved).&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/n9zbs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Now lets look at...&lt;/p&gt;

&lt;h3&gt;
  
  
  Using React's new hook-based implementation of state and effects
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://codesandbox.io/s/react-hooks-are-a-better-mental-model-f9kql"&gt;https://codesandbox.io/s/react-hooks-are-a-better-mental-model-f9kql&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 * A code sample to show how React functional components useing "hooks" are a
 * better implementation of the react mental model.
 */&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.github.com/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saveUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Pretend save that takes two seconds&lt;/span&gt;
  &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User's name has been saved to "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;initialUsername&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;({});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUsername&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialUsername&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;doFetchAndSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;doFetchAndSet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      Search
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Github Username"&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setUsername&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;hr&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Again, here is this live code running. If you try to reproduce the bug from the first example, you won't be able to.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/f9kql"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;p&gt;What insights am I missing? What did I neglect or exaggerate? Let me know!&lt;/p&gt;

</description>
      <category>javscript</category>
      <category>react</category>
      <category>functional</category>
    </item>
    <item>
      <title>Making Await More Functional in JavaScript</title>
      <dc:creator>craig martin</dc:creator>
      <pubDate>Fri, 23 Aug 2019 21:13:04 +0000</pubDate>
      <link>https://forem.com/craigmichaelmartin/making-await-more-functional-in-javascript-2le4</link>
      <guid>https://forem.com/craigmichaelmartin/making-await-more-functional-in-javascript-2le4</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/craigmichaelmartin/the-problem-with-promises-in-javascript-5h46"&gt;The Problem with Promises in Javascript&lt;/a&gt; I looked at how the API and design of promises felt casually dangerous to writing responsible and safe code.&lt;/p&gt;

&lt;p&gt;I &lt;a href="https://dev.to/craigmichaelmartin/making-javascript-promises-more-functional-jp3"&gt;included a section&lt;/a&gt; proposing a library (&lt;a href="https://github.com/craigmichaelmartin/fpromise" rel="noopener noreferrer"&gt;fPromise&lt;/a&gt;) which used a functional approach to overcome these problems.&lt;/p&gt;

&lt;p&gt;After it was published,  &lt;a href="https://twitter.com/mikesherov" rel="noopener noreferrer"&gt;Mike Sherov&lt;/a&gt; was kind enough to respond to a tweet about the article and offered his take on it: that I under-appreciated the value of the async/async syntax (that it abstracts out the tricky then/catch API, and returns us to "normal" flow) and that the problems that remain (ie, bad error handling) are problems with JavaScript itself (which TC39 is always evolving).&lt;/p&gt;

&lt;p&gt;I am very grateful for his thoughts on this, and helping elucidate a counter-narrative to the one I proposed!!&lt;/p&gt;

&lt;p&gt;Here's what Mike says:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1164169660973092864-964" src="https://platform.twitter.com/embed/Tweet.html?id=1164169660973092864"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1164169660973092864-964');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1164169660973092864&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1164180648044716032-87" src="https://platform.twitter.com/embed/Tweet.html?id=1164180648044716032"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1164180648044716032-87');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1164180648044716032&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1164170411044679682-734" src="https://platform.twitter.com/embed/Tweet.html?id=1164170411044679682"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1164170411044679682-734');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1164170411044679682&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Lets look at an example from the Problems article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been created`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be saved`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I had balked at this, as the try was "catching" too much, and used the point that if &lt;code&gt;displayName&lt;/code&gt; threw, the user would be alerted that no user was saved, even though it was. But - though the code is a bit monotonous - this is overcome-able - and was a bad job out me for not showing.&lt;/p&gt;

&lt;p&gt;If our catch is smart about error handling, this goes away.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been created`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be saved`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And if the language's evolution includes better error handling, this approach would feel better:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// (code includes fictitious catch handling by error type)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been created`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be saved`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;While this is much better, I still balk about having too much in the try. I believe catch's &lt;em&gt;should&lt;/em&gt; only catch for the exception they intend to (bad job out of me in the original post), but that the scope of what is being "tried" should be as minimal as possible.&lt;/p&gt;

&lt;p&gt;Otherwise, as the code grows, there are catch collisions:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// (code includes fictitious catch handling by error type)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been created`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mailChimpId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;postUserToMailChimp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Um...`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So here is a more narrow approach about what we are catching:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// (code includes fictitious catch handling by error type)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been created`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mailChimpId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;postUserToMailChimp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been subscribed`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be subscribed to mailing list`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be saved`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But now we find ourselves in a try/catch block "hell". Lets try to get out of it:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// (code includes fictitious catch handling by error type)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be saved`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been created`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;mailChimpId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;postUserToMailChimp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HTTPError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be subscribed to mailing list`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;mailChimpId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been subscribed`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Despite that this is responsible and safe code, it feels the most unreadable and like we're doing something wrong and ugly and working uphill against the language. Also, remember this code is using a succinct fictitious error handler, rather than the even more verbose (real) code of checking the error type and handling else re-throwing it.&lt;/p&gt;

&lt;p&gt;Which is (I believe) exactly Mike's point, that error handling (in general) needs improved, and exactly my point - that doing async code with promises is casually dangerous, as it makes dangerous code clean and ergonomic, and responsible code less readable and intuitive.&lt;/p&gt;

&lt;p&gt;So, how could this be better? What if there was -&lt;/p&gt;
&lt;h2&gt;
  
  
  Await catch handling
&lt;/h2&gt;

&lt;p&gt;What if we could do something like this?&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// (code includes fictitious await catch handling by error type)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;httpError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be saved`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been created`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;httpError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be subscribed to mailing list`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been subscribed`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This reads nicely and is safe and responsible! We are catching exactly the error type we intend to. Any other error causes the await to "throw". &lt;/p&gt;

&lt;p&gt;And it could be used with multiple error types. Eg,&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// (code includes fictitious catch handling by error type)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;FooError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BarThing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  How close can we get to this in userland?
&lt;/h2&gt;

&lt;p&gt;Pretty close. Introducing &lt;a href="https://github.com/craigmichaelmartin/fawait" rel="noopener noreferrer"&gt;fAwait&lt;/a&gt; (as in functional-await).&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;fa&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fawait&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;httpError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;HTTPError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;FooError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BarThing&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Thanks for reading!&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/craigmichaelmartin" rel="noopener noreferrer"&gt;
        craigmichaelmartin
      &lt;/a&gt; / &lt;a href="https://github.com/craigmichaelmartin/fawait" rel="noopener noreferrer"&gt;
        fawait
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A javascript library for making await more functional
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;&lt;code&gt;fAwait&lt;/code&gt;&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://travis-ci.org/craigmichaelmartin/fawait" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ba1945c676bdcecfc97d53f0d705460f38c3dd45023e387e913cc02259f1719f/68747470733a2f2f7472617669732d63692e6f72672f63726169676d69636861656c6d617274696e2f6661776169742e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/craigmichaelmartin/fawait" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4e44fecea5e36122caf0884a5feb96d7352de9103f4b324d12b9dc55533aff8d/68747470733a2f2f636f6465636f762e696f2f67682f63726169676d69636861656c6d617274696e2f6661776169742f6272616e63682f6d61737465722f67726170682f62616467652e737667" alt="codecov"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is &lt;code&gt;fAwait&lt;/code&gt;?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;fAwait&lt;/code&gt; is a javascript library for working with the &lt;code&gt;await&lt;/code&gt; syntax in a more functional way.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How To Use It&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Wrap your promise with the &lt;code&gt;fa&lt;/code&gt; function, and provide error types you want to catch, and you'll receive an array you can unpack to those values. If error types are provided, and the promise rejects with one not specified, it will be thrown. Error types can be the built-ins, or your own custom error types. If no error types are provided, all will be caught.&lt;/p&gt;
&lt;div class="highlight highlight-source-js notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; fa &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;require&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s"&gt;'fawait'&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-s1"&gt;data&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;myError&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-en"&gt;fa&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-s1"&gt;promise&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-v"&gt;MyError&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-c"&gt;// If the promise resolves, data will be defined.&lt;/span&gt;
&lt;span class="pl-c"&gt;// If the promise rejects with my own custom error, myError will be defined.&lt;/span&gt;
&lt;span class="pl-c"&gt;// If the promise rejects with any other error, the await will&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/craigmichaelmartin/fawait" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>javascript</category>
      <category>async</category>
      <category>await</category>
      <category>functional</category>
    </item>
    <item>
      <title>Making JavaScript Promises More Functional</title>
      <dc:creator>craig martin</dc:creator>
      <pubDate>Fri, 23 Aug 2019 16:54:51 +0000</pubDate>
      <link>https://forem.com/craigmichaelmartin/making-javascript-promises-more-functional-jp3</link>
      <guid>https://forem.com/craigmichaelmartin/making-javascript-promises-more-functional-jp3</guid>
      <description>&lt;p&gt;[&lt;em&gt;This article was extracted out of &lt;a href="https://dev.to/craigmichaelmartin/the-problem-with-promises-in-javascript-5h46"&gt;The Problem with Promises in JavaScript&lt;/a&gt;. It was the final section, but given that it is only one possible solution to the problems enumerated, thought it should live separately. After the short introduction, it is unedited from when it was the final section of the mentioned article.&lt;/em&gt;]&lt;/p&gt;

&lt;p&gt;A few years ago I created a new repo for a Node-backend web app, and spent some time considering how to deal with promises in my code. In other Node side-projects, I had begun to see some recurring issues with promises: that the API seemed to have the best ergonomics when used dangerously, that they lacked a convenient API to safely work with data, and that rejected promises and unintended runtime exceptions were co-mingled and left for the developer to sort out.&lt;/p&gt;

&lt;p&gt;You can read more about these issues in &lt;a href="https://dev.to/craigmichaelmartin/the-problem-with-promises-in-javascript-5h46"&gt;The Problem with Promises in JavaScript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This article is one (out of an infinite number of solutions to these problems - and probably a really bad one) thought experiment on what might be a solution.. which turned into a library: &lt;a href="https://github.com/craigmichaelmartin/fpromise" rel="noopener noreferrer"&gt;fPromise&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/craigmichaelmartin" rel="noopener noreferrer"&gt;
        craigmichaelmartin
      &lt;/a&gt; / &lt;a href="https://github.com/craigmichaelmartin/fpromise" rel="noopener noreferrer"&gt;
        fpromise
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Making promise usage safe, convenient, and readable.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;&lt;code&gt;fPromise&lt;/code&gt;&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://travis-ci.org/craigmichaelmartin/fpromise" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c6cc1b818a9753c58fccdd62cc811df30400bc3933f607a4534d7a728fb3fdd8/68747470733a2f2f7472617669732d63692e6f72672f63726169676d69636861656c6d617274696e2f6670726f6d6973652e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://greenkeeper.io/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ee02cc729f3cada0aaa37d6d0c5911e4b6a81451556192ad6d3791fd90216d24/68747470733a2f2f6261646765732e677265656e6b65657065722e696f2f63726169676d69636861656c6d617274696e2f6670726f6d6973652e737667" alt="Greenkeeper badge"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/craigmichaelmartin/fpromise" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8cc14c65eae22d8b5c3796e1a6e85675b166dcaee9b3ed5bb8b35fd23cbc1e9b/68747470733a2f2f636f6465636f762e696f2f67682f63726169676d69636861656c6d617274696e2f6670726f6d6973652f6272616e63682f6d61737465722f67726170682f62616467652e737667" alt="codecov"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install --save fpromise&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is &lt;code&gt;fPromise&lt;/code&gt;?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;fPromise&lt;/code&gt; is a javascript library for working with promises.&lt;/p&gt;
&lt;p&gt;It seeks to resolve &lt;a href="https://dev.to/thecraigmichael/the-problem-with-promises-in-javascript-5h46" rel="nofollow"&gt;three problems with promises&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Promises have an API which encourages casually dangerous code&lt;/li&gt;
&lt;li&gt;Promises co-mingle rejected promises with unintended native exceptions&lt;/li&gt;
&lt;li&gt;Promises lack a suite of convenient API methods to work with results&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(For background, and probably a better explanation about this library, read
&lt;a href="https://dev.to/thecraigmichael/the-problem-with-promises-in-javascript-5h46" rel="nofollow"&gt;that article about the problems with promises&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fPromise&lt;/code&gt; solves these issues by adding a layer of abstraction within promises - re-designing promises's two path design (resolved/rejected) into three paths:
a data path, a non-native exception path (ie, for promises rejected by your
own intentions), and a native exception path.&lt;/p&gt;
&lt;p&gt;With these three paths, we can have an API which is safe, intentional,
convenient, and more readable.&lt;/p&gt;
&lt;p&gt;Importantly this abstraction:&lt;/p&gt;
&lt;ul class="contains-task-list"&gt;
&lt;li class="task-list-item"&gt;
 using promises&lt;/li&gt;
&lt;li class="task-list-item"&gt;
 leave the promise prototype untouched&lt;/li&gt;
&lt;li class="task-list-item"&gt;
 provide a safe API for…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/craigmichaelmartin/fpromise" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;If you haven't read the &lt;a href="https://dev.to/craigmichaelmartin/the-problem-with-promises-in-javascript-5h46"&gt;The Problem with Promises in JavaScript&lt;/a&gt;, you may want to.&lt;/p&gt;

&lt;p&gt;So, lets begin from a thought experiment about what better promises might have looked like, and see if we can get there in userland code. By "better" - I mean immune to the problems above.&lt;/p&gt;

&lt;h1&gt;
  
  
  What might a "better" Promise implementation look like?
&lt;/h1&gt;

&lt;p&gt;It feels right that &lt;code&gt;await&lt;/code&gt; throws for native exceptions (just like regularly synchronous code would). What is not ideal is that non-native errors are in that bucket, and so have to be caught, and with the new block scopes decreasing readability and making the code more disjointed. &lt;/p&gt;

&lt;p&gt;Imagine if promises used rejected promises only for native runtime exceptions, and used a special object for data/issues. Lets call that special object an Either. It is iterable to a two element array with data as the first element, issue as the second. To our earlier point, it also specifies methods like map/imap (issue map) and tap/itap (issue tap) which its two implementations (Data and Issue) implement. Data has no-ops for imap and itap. Issue has no-ops for map and tap. &lt;code&gt;map&lt;/code&gt;/&lt;code&gt;imap&lt;/code&gt; re-wrap the result as Data/Issue respectively, unless explicitly transformed to the other. The tap methods are side-effect only who's returns are not used.&lt;/p&gt;

&lt;p&gt;Promise.resolve creates a "regular" promise wrapping the value in Data. Promise.reject creates a "regular" promise wrapping the value in Issue &lt;em&gt;if&lt;/em&gt; the reject is not a native error; otherwise, it creates an actually "rejected" promise.&lt;/p&gt;

&lt;p&gt;We could write code like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Made up API below!&lt;/span&gt;

&lt;span class="c1"&gt;// data-access/user.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInsertSQL&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="c1"&gt;// As long as there is no native Exceptions, this returns a&lt;/span&gt;
&lt;span class="c1"&gt;// promise in the "regular" state.&lt;/span&gt;

&lt;span class="c1"&gt;// service/user.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getStandardLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_creation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;   &lt;span class="c1"&gt;// Fictional&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parseUserFromDB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;              &lt;span class="c1"&gt;// Fictional&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                        &lt;span class="c1"&gt;// Fictional&lt;/span&gt;

&lt;span class="c1"&gt;// controllers/user.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// No need to use try/catch, as everything is in the "regular" state&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Fictional&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errorToCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;IntegrityError&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;422&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;errorToCode&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;postEmailToMailChimp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tapError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Features of this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rejected promises are only used for native exceptions, so no need to use a try/catch block - more readable, cohesive code. Everything else is in the "regular" path, but as a Data or Issue.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;map&lt;/code&gt;, &lt;code&gt;tap&lt;/code&gt;, &lt;code&gt;itap&lt;/code&gt; helper utilities which apply the functions to "regular" path promise values. (Remember, map/tap are no-ops on Error, imap/itap are no-ops on Data.)&lt;/li&gt;
&lt;li&gt;"regular" promises values (Data|Either) destructure to an array with the data or issue (but, again, never native runtime errors - those throw (and could here be caught in a try/catch, but no one programs for that level of fear: eg &lt;code&gt;try { Math.random() } catch (err) { console.log('Just in case I typo-ed the string "Math" }&lt;/code&gt;))&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;await&lt;/code&gt; allows us to stay in the callstack (allowing return)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;This to me feels like promises done right.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How close can we get to the above code?
&lt;/h2&gt;

&lt;p&gt;We can actually get pretty close.&lt;/p&gt;

&lt;p&gt;We'll&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[x] use promises&lt;/li&gt;
&lt;li&gt;[x] leave the promise prototype untouched&lt;/li&gt;
&lt;li&gt;[x] provide a safe API for using them which isn't casually dangerous&lt;/li&gt;
&lt;li&gt;[x] ensure unintentional runtime errors are not handled (and so throw when awaited)&lt;/li&gt;
&lt;li&gt;[x] provide utility methods for working with the data&lt;/li&gt;
&lt;li&gt;[x] increase readability/cohesion (vs try blocks)&lt;/li&gt;
&lt;li&gt;[x] keeps control in main call block (so returns work)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By providing a safe API within the Promise structure, this "library" we'll make can be used anywhere promises are, without hijacking the prototype or needing to introduce a new primitive.&lt;/p&gt;

&lt;p&gt;We'll create an Either type which specify&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;map&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;imap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;itap&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and ensures it is iterable (destructure-able) to a two element array.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Data&lt;/code&gt; and &lt;code&gt;Issue&lt;/code&gt; implement this Either interface.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;          &lt;span class="c1"&gt;// transform the data by applying the fn&lt;/span&gt;
  &lt;span class="na"&gt;imap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;            &lt;span class="c1"&gt;// no-op (method targets Issue)&lt;/span&gt;
  &lt;span class="na"&gt;bmap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;    &lt;span class="c1"&gt;// run respective fn on data&lt;/span&gt;
  &lt;span class="na"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;     &lt;span class="c1"&gt;// runs side effect fn on data&lt;/span&gt;
  &lt;span class="na"&gt;itap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;            &lt;span class="c1"&gt;// no-op (method targets Issue)&lt;/span&gt;
  &lt;span class="na"&gt;btap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="c1"&gt;// run respective sideeffect fn on data&lt;/span&gt;
  &lt;span class="na"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;isData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;isIssue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Issue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;            &lt;span class="c1"&gt;// no-op (method targets Data)&lt;/span&gt;
  &lt;span class="na"&gt;imap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;        &lt;span class="c1"&gt;// transform the issue by applyin the fn&lt;/span&gt;
  &lt;span class="na"&gt;bmap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;   &lt;span class="c1"&gt;// run respective fn on issue&lt;/span&gt;
  &lt;span class="na"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;            &lt;span class="c1"&gt;// no-op (method target Data)&lt;/span&gt;
  &lt;span class="na"&gt;itap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;   &lt;span class="c1"&gt;// runs side effect fn on issue&lt;/span&gt;
  &lt;span class="na"&gt;btap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;Issue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="c1"&gt;//run respective sideeffect f on issue&lt;/span&gt;
  &lt;span class="na"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;isData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;isIssue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We'll need an &lt;code&gt;fp&lt;/code&gt; which transforms a current promise to play by our safe rules.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ensureData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;Data&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nativeExceptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nx"&gt;EvalError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RangeError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ReferenceError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SyntaxError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TypeError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;URIError&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ensureIssue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;nativeException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ensureData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ensureIssue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To make these more functional, we could also add:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureIssue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;imap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;imap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureIssue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;imap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bmap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;bmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureIssue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;bmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureIssue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;itap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;itap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureIssue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;itap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;btap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;btap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ensureIssue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;btap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;To re-write the fictional promise code from above, it's pretty straight forward. We:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;wrap the initial promise with a &lt;code&gt;fp&lt;/code&gt; to get the promise to play by our rules (again, it remains a completely regular promise).&lt;/li&gt;
&lt;li&gt;(await promise) before we can call our utility methods. This is because our utility methods are on the Either that the promise resolves to, not the promise itself. To the point above, we are not touching/modifying promises, just layering on top of them.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// data-access/user.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInsertSQL&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;

&lt;span class="c1"&gt;// service/user.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getStandardLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_creation))
    .map(User.parseUserFromDB)
    .itap(logError)

// controllers/user.js
const postHandler = async (userDate, response) =&amp;gt; {
  const [user, error] = await save(userData);
  // ...
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If we wanted to use the more functional approach, no need for initially wrapping the promise:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// data-access/user.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInsertSQL&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// service/user.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getStandardLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_creation)))
  .then(...map(User.parseUserFromDB))
  .then(...itap(logError))

// controllers/user.js
const postHandler = async (userDate, response) =&amp;gt; {
  const [user, error] = await save(userData);
  // ...
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Notice for both of these, all of are conditions are met. We are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[x] using promises&lt;/li&gt;
&lt;li&gt;[x] leave the promise prototype untouched&lt;/li&gt;
&lt;li&gt;[x] provide a safe API for using them which isn't casually dangerous&lt;/li&gt;
&lt;li&gt;[x] ensures unintentional runtime errors are not handled&lt;/li&gt;
&lt;li&gt;[x] provides utility methods for working with the data&lt;/li&gt;
&lt;li&gt;[x] increases readability (vs try blocks)&lt;/li&gt;
&lt;li&gt;[x] keeps control in main call block (so returns work)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we want to move even further in the functional direction, we could:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// data-access/user.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInsertSQL&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// service/user.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;save&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;getStandardLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_creation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parseUserFromDB&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nf"&gt;itap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="c1"&gt;// controllers/user.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;//...&lt;/span&gt;
    &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;//...&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you're interested in this fPromise idea, &lt;a href="https://github.com/craigmichaelmartin/fpromise" rel="noopener noreferrer"&gt;help with it on github&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/craigmichaelmartin" rel="noopener noreferrer"&gt;
        craigmichaelmartin
      &lt;/a&gt; / &lt;a href="https://github.com/craigmichaelmartin/fpromise" rel="noopener noreferrer"&gt;
        fpromise
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Making promise usage safe, convenient, and readable.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;&lt;code&gt;fPromise&lt;/code&gt;&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://travis-ci.org/craigmichaelmartin/fpromise" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c6cc1b818a9753c58fccdd62cc811df30400bc3933f607a4534d7a728fb3fdd8/68747470733a2f2f7472617669732d63692e6f72672f63726169676d69636861656c6d617274696e2f6670726f6d6973652e7376673f6272616e63683d6d6173746572" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://greenkeeper.io/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/ee02cc729f3cada0aaa37d6d0c5911e4b6a81451556192ad6d3791fd90216d24/68747470733a2f2f6261646765732e677265656e6b65657065722e696f2f63726169676d69636861656c6d617274696e2f6670726f6d6973652e737667" alt="Greenkeeper badge"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/craigmichaelmartin/fpromise" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8cc14c65eae22d8b5c3796e1a6e85675b166dcaee9b3ed5bb8b35fd23cbc1e9b/68747470733a2f2f636f6465636f762e696f2f67682f63726169676d69636861656c6d617274696e2f6670726f6d6973652f6272616e63682f6d61737465722f67726170682f62616467652e737667" alt="codecov"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install --save fpromise&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;What is &lt;code&gt;fPromise&lt;/code&gt;?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;fPromise&lt;/code&gt; is a javascript library for working with promises.&lt;/p&gt;
&lt;p&gt;It seeks to resolve &lt;a href="https://dev.to/thecraigmichael/the-problem-with-promises-in-javascript-5h46" rel="nofollow"&gt;three problems with promises&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Promises have an API which encourages casually dangerous code&lt;/li&gt;
&lt;li&gt;Promises co-mingle rejected promises with unintended native exceptions&lt;/li&gt;
&lt;li&gt;Promises lack a suite of convenient API methods to work with results&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(For background, and probably a better explanation about this library, read
&lt;a href="https://dev.to/thecraigmichael/the-problem-with-promises-in-javascript-5h46" rel="nofollow"&gt;that article about the problems with promises&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fPromise&lt;/code&gt; solves these issues by adding a layer of abstraction within promises - re-designing promises's two path design (resolved/rejected) into three paths:
a data path, a non-native exception path (ie, for promises rejected by your
own intentions), and a native exception path.&lt;/p&gt;
&lt;p&gt;With these three paths, we can have an API which is safe, intentional,
convenient, and more readable.&lt;/p&gt;
&lt;p&gt;Importantly this abstraction:&lt;/p&gt;
&lt;ul class="contains-task-list"&gt;
&lt;li class="task-list-item"&gt;
 using promises&lt;/li&gt;
&lt;li class="task-list-item"&gt;
 leave the promise prototype untouched&lt;/li&gt;
&lt;li class="task-list-item"&gt;
 provide a safe API for…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/craigmichaelmartin/fpromise" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;or check out similar-&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;em&gt;Actually Good&lt;/em&gt; Projects in this space
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/DavidWells/56089265ab613a1f29eabca9fc68a3c6" rel="noopener noreferrer"&gt;https://gist.github.com/DavidWells/56089265ab613a1f29eabca9fc68a3c6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/gunar/go-for-it" rel="noopener noreferrer"&gt;https://github.com/gunar/go-for-it&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/majgis/catchify" rel="noopener noreferrer"&gt;https://github.com/majgis/catchify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/scopsy/await-to-js" rel="noopener noreferrer"&gt;https://github.com/scopsy/await-to-js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/fluture-js/Fluture" rel="noopener noreferrer"&gt;https://github.com/fluture-js/Fluture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/russellmcc/fantasydo" rel="noopener noreferrer"&gt;https://github.com/russellmcc/fantasydo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Articles About This Stuff From Smart People:
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/@gunar/async-control-flow-without-exceptions-nor-monads-b19af2acc553" rel="noopener noreferrer"&gt;https://medium.com/@gunar/async-control-flow-without-exceptions-nor-monads-b19af2acc553&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.grossman.io/how-to-write-async-await-without-try-catch-blocks-in-javascript/" rel="noopener noreferrer"&gt;https://blog.grossman.io/how-to-write-async-await-without-try-catch-blocks-in-javascript/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jessewarden.com/2017/11/easier-error-handling-using-asyncawait.html" rel="noopener noreferrer"&gt;http://jessewarden.com/2017/11/easier-error-handling-using-asyncawait.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.freecodecamp.org/avoiding-the-async-await-hell-c77a0fb71c4c" rel="noopener noreferrer"&gt;https://medium.freecodecamp.org/avoiding-the-async-await-hell-c77a0fb71c4c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@dominic.mayers/async-await-without-promises-725e15e1b639" rel="noopener noreferrer"&gt;https://medium.com/@dominic.mayers/async-await-without-promises-725e15e1b639&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@dominic.mayers/on-one-hand-the-async-await-framework-avoid-the-use-of-callbacks-to-define-the-main-flow-in-812317d19285" rel="noopener noreferrer"&gt;https://medium.com/@dominic.mayers/on-one-hand-the-async-await-framework-avoid-the-use-of-callbacks-to-define-the-main-flow-in-812317d19285&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/sadarshannaiynar/capture-error-and-data-in-async-await-without-try-catch-1no2"&gt;https://dev.to/sadarshannaiynar/capture-error-and-data-in-async-await-without-try-catch-1no2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@pyrolistical/the-hard-error-handling-case-made-easy-with-async-await-597fd4b908b1" rel="noopener noreferrer"&gt;https://medium.com/@pyrolistical/the-hard-error-handling-case-made-easy-with-async-await-597fd4b908b1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/woudsma/fe8598b1f41453208f0661f90ecdb98b" rel="noopener noreferrer"&gt;https://gist.github.com/woudsma/fe8598b1f41453208f0661f90ecdb98b&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>promises</category>
      <category>javascript</category>
      <category>async</category>
      <category>await</category>
    </item>
    <item>
      <title>The Problem with Promises in JavaScript</title>
      <dc:creator>craig martin</dc:creator>
      <pubDate>Fri, 16 Aug 2019 02:32:22 +0000</pubDate>
      <link>https://forem.com/craigmichaelmartin/the-problem-with-promises-in-javascript-5h46</link>
      <guid>https://forem.com/craigmichaelmartin/the-problem-with-promises-in-javascript-5h46</guid>
      <description>&lt;p&gt;Spending a lot of time in Node recently, I keep coming accross 3 recurring problems with promises:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Promises have an API which encourages casually dangerous code&lt;/li&gt;
&lt;li&gt;Promises lack a convenient API to safely work with data.&lt;/li&gt;
&lt;li&gt;Promises co-mingle rejected promises and unintended runtime exceptions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While the &lt;code&gt;await&lt;/code&gt; syntax is happy addition to the language, and part of a solution to these problems, its value - increasing readability and keeping control in the original callstack (ie allowing for returns) - is unrelated to the second two issues, and only sometimes mitigating of the first problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Promises have an API which encourages casually dangerous code.
&lt;/h2&gt;

&lt;p&gt;Lets take an example of saving a user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Promises (without using await)&lt;/span&gt;
&lt;span class="c1"&gt;// Casually dangerous code&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been created`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be saved`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This code looks readable and explicit: a clearly defined path for success and for failure.&lt;/p&gt;

&lt;p&gt;However, while trying to be explicit, we have attached our &lt;code&gt;catch&lt;/code&gt; not just to the &lt;code&gt;saveUser&lt;/code&gt; request, but also to the success path. Thus, if the then throws (eg, the displayName function throws) then the user will be notified that no user was saved, even though it was.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One might think, lets switch the order of the then/catch, so that the catch is attached to the saveUser call directly. This introduces another issue, we'll look at further below (as the third issue).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Using await doesn't necessarily help. It is agnostic to using the API correctly, and because of its block scoping it also makes it easier and prettier to write it dangerously as above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Promises with Async/Await doesn't necessarily help&lt;/span&gt;
&lt;span class="c1"&gt;// Casually dangerous code&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;has&lt;/span&gt; &lt;span class="nx"&gt;been&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt;&lt;span class="s2"&gt;`);
  } catch {
    createToast(`&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="nx"&gt;could&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt;&lt;span class="s2"&gt;`));
  }
};
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Because of the block scoping, it is more convenient to include the createToast line in the try, but then this code has the same issue as above.&lt;/p&gt;

&lt;p&gt;The responsible refactor of this using native promises &lt;em&gt;looks&lt;/em&gt; worse/ugly/bad/complicated. Lets look at the case of not using &lt;code&gt;await&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;For the case of not using &lt;code&gt;await&lt;/code&gt;, two anonymous functions in the correct order (error function first? success function first?) must be passed to the then, which feels less organized than using an explicit &lt;code&gt;catch&lt;/code&gt; block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Promises done responsibly _look_ worse/ugly/bad/complicated :(&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been created`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be saved`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To be clear, this isn't a bad API in itself. But considering the rightful intention of being explicit as a developer, there is a temptation of using a named function for each, rather than one &lt;code&gt;then&lt;/code&gt; with the two callbacks. The responsible code is less explicit and readable than dangerous code - &lt;strong&gt;it is temptingly dangerous to misuse the API - while feeling more explicit and readable!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The responsible refactor using &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; &lt;em&gt;looks even more so&lt;/em&gt; wrong/ugly/bad/complicated. Having to define variables in a higher scope feels like a bad control flow. It feels like we're working against the language:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Promises done responsibly _look_ worse/ugly/bad/complicated :(&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSave&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User could not be saved`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;createToast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`User &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; has been created`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Notice the code above isn't even correct. We'd need to return from the &lt;code&gt;catch&lt;/code&gt; (something I try to avoid as it further confuses control flow - especially if there is a finally) or wrap everything after the try if an &lt;code&gt;if (user) { /*...*/ }&lt;/code&gt; block - creating another block. It feels like we're working uphill.&lt;/p&gt;




&lt;p&gt;It's also worth noting that the API is &lt;em&gt;also&lt;/em&gt; unintuitive (but this time the other way!) when chaining multiple &lt;code&gt;then&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;Whereas the examples above are dangerous because the &lt;code&gt;catch&lt;/code&gt; is meant to be attached to the "root" async call (the HTTP request) - &lt;strong&gt;there is also a danger with long chains of thinking the &lt;code&gt;catch&lt;/code&gt; is associated with the most recent then.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;(It's neither attached to the root promise nor the most recent promise - it is attached to the entire chain preceding it.)&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Casually dangerous code&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userPostHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queueWelcomeEmailForLaterAttempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;which looks and reads cleanly, compared to the responsible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Promises done responsibly _look_ worse/ugly/bad/complicated :(&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userPostHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queueWelcomeEmailForLaterAttempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;






&lt;p&gt;Lets go further with the example above, to see one last way the API is casually dangerous: lets add logging for if the user can't be created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Dangerous code&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userPostHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;writeIssueToLog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queueWelcomeEmailForLaterAttempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What we want is to write the issue to our logs if the user save fails.&lt;/p&gt;

&lt;p&gt;However, because our catch doesn't re-throw or explicitly reject, it returns a resolved promise and so the next then (sendWelcomeEmail) will run, and because there is no user, it will throw, and we'll create a queued email for a non-existing user. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The casual promise API makes unintentionally recovering from an exception easy/sleek/elegant.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Again, the fix looks bad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Promises done responsibly _look_ worse/ugly/bad/complicated :(&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userPostHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawUserData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;writeIssueToLog&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queueWelcomeEmailForLaterAttempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Wrapping up this section, we've seen how promise's API for handling errors while seemingly sleek, is casually dangerous: both due to the readability and convenience of catching separately from the &lt;code&gt;then&lt;/code&gt; (ie, using an explicit catch function - which if in a chain includes errors not just from the "root" promise, nor from the most recent promise, but from any promise in the chain), as well as by fostering an unintentional recovery of errors.&lt;/p&gt;

&lt;p&gt;While the addition of the &lt;code&gt;async&lt;/code&gt; operator can help, it does so within a try scope - making the right code look disjointed, and irresponsible code (placing too much in the try) look cleaner/sleeker.&lt;/p&gt;

&lt;p&gt;I would prefer an API which at a minimum optimizes aesthetics and readability (by working with the language) for the responsible behavior, and preferably which precludes irresponsible or casually dangerous code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Promises lack a convenient API to safely work with data.
&lt;/h2&gt;

&lt;p&gt;In the section above, we looked at how the existing promise API is temptingly dangerous (using two explicit named functions vs one with anonymous parameters for each function), and how it fosters unintentionally recovering from errors.&lt;/p&gt;

&lt;p&gt;This second case is a problem only because the promise API doesn't offer more helpers.&lt;/p&gt;

&lt;p&gt;In the last example above where our &lt;code&gt;.catch(logError)&lt;/code&gt; inadvertently resolved the error, what we were really wanting was something else: a &lt;code&gt;tap&lt;/code&gt; side-effect function for errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Promises co-mingle rejected promises and unintended runtime exceptions
&lt;/h2&gt;

&lt;p&gt;Apart from how the API is structured - promises have another major flaw: &lt;strong&gt;they treat unintentional native runtime exceptions and intentional rejected promises - which are two drastically different intentions - in the same "path".&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userPostHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawUserData&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;saveUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;postEmailToMailChimp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What this code is trying to express is pretty straightforward. (I want to save a user and post their email to my mailchimp list and log if there is an issue).&lt;/p&gt;

&lt;p&gt;However, I accidentally typo'd the function name as "MailChimp" instead of "Mailchimp" - and rather than the runtime error alerting me while developing - I now have to hope that I look at the log - which I intended for mailchimp issues, not basic programming issues!&lt;/p&gt;

&lt;p&gt;In explaining the root issue here with promises, I abbreviated the behavior slightly: promises treat all errors (not just native errors) the same as rejected promises. Treating &lt;code&gt;throw&lt;/code&gt; and &lt;code&gt;Promise.reject&lt;/code&gt; synonymously seems reasonable. What does not seem reasonable is using this one "path" to handle two worlds-different "types" of errors without distinction: "strategic" errors (eg &lt;code&gt;saveUser(user)&lt;/code&gt; throwing a custom Integrity error), and basic javascript runtime errors (eg saveUsr(user) having a typo and throwing a ReferenceError). These are two fundamentally different realties, but they are bundled together in the same "rejected promise" path.&lt;/p&gt;

&lt;p&gt;With promises, there are really three paths: the data "path", a non-native error "path" (eg, custom, business-logic errors), and a native error "path", yet the API does not make this distinction: and treats all errors and rejected promises the same.&lt;/p&gt;




&lt;p&gt;[Two updates]&lt;/p&gt;

&lt;p&gt;[Update] This article previously continued with a theoretical section on what "better" Promises might look like... "What comes next is one (out of an infinite number of solutions to these problems - and probably a really bad one) thought experiment on what might be a solution.. which turned into a library." If you're interested you can see read it here, &lt;a href="https://dev.to/craigmichaelmartin/making-javascript-promises-more-functional-jp3"&gt;Making JavaScript Promises More Functional&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[Update] &lt;a href="https://twitter.com/mikesherov"&gt;Mike Sherov&lt;/a&gt; was kind enough to respond to a tweet about this article and offered his take on this: that I under-appreciated the value of the &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;async&lt;/code&gt; syntax (that it abstracts out the tricky &lt;code&gt;then&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; API, and returns us to "normal" flow) and that the problems that remain (ie, bad error handling) are problems with JavaScript itself (which TC39 is always evolving). I expand on that idea, including the creation of a very simple library, in &lt;a href="https://dev.to/craigmichaelmartin/making-await-more-functional-in-javascript-2le4"&gt;Making Await More Functional in Javascript&lt;/a&gt;&lt;/p&gt;

</description>
      <category>promises</category>
      <category>javascript</category>
      <category>async</category>
      <category>await</category>
    </item>
    <item>
      <title>User Types and Roles in an Activity-based Permission Systems</title>
      <dc:creator>craig martin</dc:creator>
      <pubDate>Fri, 04 Jan 2019 03:01:53 +0000</pubDate>
      <link>https://forem.com/craigmichaelmartin/decoupling-user-profiles-from-user-roles-in-activity-based-permission-systems-1lm</link>
      <guid>https://forem.com/craigmichaelmartin/decoupling-user-profiles-from-user-roles-in-activity-based-permission-systems-1lm</guid>
      <description>&lt;p&gt;&lt;em&gt;Decoupling User Types from User Roles in Activity-based Permission Systems&lt;/em&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  TLDR;
&lt;/h4&gt;

&lt;p&gt;Lets say we are developing an app. In our app we should have lots of granular, atomic permissions. We should support roles (groupings of permissions) but as something defined by admin-users for their organization, and so be 100% arbitrary to us. These roles should exist within Profile types, which &lt;em&gt;are&lt;/em&gt; defined by us, and are used to know which "type" of user we are dealing with. A user can have multiple roles within and across multiple profiles, but can only be acting as one profile at a time. Our app code, when dealing with a user, can check their Profile (ie &lt;code&gt;user.is(Profile)&lt;/code&gt; to answer the question "where should we send them?") or perform permission checks (ie, &lt;code&gt;user.can(Operation, Object)&lt;/code&gt; to answer the question "what should they be able to do/see when they get there?").&lt;/p&gt;

&lt;h2&gt;
  
  
  Concepts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Permissions&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Permission is a granular activity-based access control.&lt;/li&gt;
&lt;li&gt;Permissions are specified by the development team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Profiles&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Profile is a supported user type in the app.&lt;/li&gt;
&lt;li&gt;Profiles are specified by the development team.&lt;/li&gt;
&lt;li&gt;Profiles (user types) are used to determined &lt;em&gt;where&lt;/em&gt; a user should go based. They correspond with tracks built the app (eg, which dashboard to go to).&lt;/li&gt;
&lt;li&gt;For each Profile an organization creates their own roles.&lt;/li&gt;
&lt;li&gt;A user may have roles in more than one profile.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Roles&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Role is a group of permissions for a Profile.&lt;/li&gt;
&lt;li&gt;Roles are not specified by the development team and are completely arbitrary, and instead are specified by privileged users for their organization.&lt;/li&gt;
&lt;li&gt;A user may have more than one role per profile.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;User&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A user has exactly one active profile (which has at least one role), but can switch profiles.&lt;/li&gt;
&lt;li&gt;A user may have roles in multiple organizations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Organization&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Organization is a grouping entity with an internal hierarchy.&lt;/li&gt;
&lt;li&gt;Roles exist for a Profile for an Organization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Profiles exist to answer questions related to which "type" of user the app is dealing with. Permissions exist to answer questions related to what access the user can have. (EG, Profile: "Should the user be routed to the admin or affiliate dashboard?" vs Permission: "What should they see and be able to edit once they are routed?") Roles exist to in service of making permissions manageable.&lt;/p&gt;

&lt;p&gt;Without profiles, you end up with a set of faux permissions - "permissions" which really are just interested in what type the user is (eg, canSeeAdminDashboard and canSeeAffiliateDashboard are really just questions about what is the type of user using the app).&lt;/p&gt;

&lt;p&gt;Without roles, every user is a one-off set of permissions. For example, If you're creating multiple users for managing invoices, you'd have to re-select exactly the same permissions for each user, including months later after you hire another person to manage invoices. Or, suppose for example a new invoice feature comes out later. You'd have to remember which users are doing invoice work, and update each of them with this new permission.&lt;/p&gt;

&lt;p&gt;Without organizations, roles would have to be global and governed by the development team. Instead, each organization in the system can configure their own roles for their applicable profiles - choosing permissions defined by the development team for that profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schema
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;operation               # actions types in the system (read, edit, create, etc)
- id

object                  # entity types to be acted upon (invoices, customers, etc)
- id

permission              # atomic abilities in the app
- id
- operation_id
- object_id

role                    # an organization's group of permissions for a profile
- id
- value
- label
- profile_id
- organization_id

role_permission         # specifies which permissions are in a role
- id
- role_id
- permission_id

profile                 # a supported user identity type in the app
- id
- value
- label

profile_permission      # specifies which profiles a permission is valid for
- id
- permission_id
- profile_id

organization
- id

user
- id
- active_profile_id

user_role               # specifies the roles a user has
- user_id
- role_id

# There would be no `user_profile` table, as access to a profile is a permission
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;User&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;is(Profile)&lt;/code&gt; - returns whether the user is actively acting as a certain profile type (answering questions like "where should we send this user?")&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;can(Operation, Object, Organization?)&lt;/code&gt; - iterates through the user's roles (for a specific organization if supplied) for their active profile, to identify if they have permission (answering questions like "what resources should the user be able to see/change?")&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;switchProfile(Profile)&lt;/code&gt; - changes the user's active profile&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Making it Less Abstract: An Example
&lt;/h2&gt;

&lt;p&gt;Let's say you and I create an app for lawn care businesses.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Lawn Care Owners&lt;/em&gt; log in to create clients, create employees, assign jobs to employees, send invoices to their clients, and write monthly newsletters about lawn care tips to their clients.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Lawn Care Workers&lt;/em&gt; log in to see their schedule.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Clients&lt;/em&gt; log in to pay their invoices, and see past invoices.&lt;/li&gt;
&lt;li&gt;As part of an affiliate-system, &lt;em&gt;Home Owner Associations&lt;/em&gt; can log in to see clients in their neighborhoods.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Product Marketing Companies&lt;/em&gt; can log in to post ads to this app, since its free to the business owner.&lt;/li&gt;
&lt;li&gt;Finally, &lt;em&gt;Internal Staff&lt;/em&gt; (you and I and our employees) can log in to see data and metrics and charts and stuff.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thus, we create these six Profiles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lawn Care Administrator&lt;/li&gt;
&lt;li&gt;Lawn Care Worker&lt;/li&gt;
&lt;li&gt;Client&lt;/li&gt;
&lt;li&gt;Homeowner Association Rep&lt;/li&gt;
&lt;li&gt;Brand Rep&lt;/li&gt;
&lt;li&gt;Internal Staff&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While, each profile is known and has special meaningful to us, roles are all user-generated and are never referenced or known in our code.&lt;/p&gt;

&lt;p&gt;Let's start by looking at the first three.&lt;/p&gt;

&lt;p&gt;In the beginning, the owner makes one role within each profile, and assigns it to himself. As the company grows, he hires employees for each of these, and soon has multiple employees type: Just in administration, a manager to schedule clients and assign lawn care workers to them; a bookkeeper to see the paid/unpaid finances; a marketing intern to write up the newsletters. Similarly, there arises a hierarchy within his growing crew of lawn care workers, constraining permissions for new guys and allowing the full breadth of permissions for his team lead. Lastly, as commercial clients are taken on, a role with different permissions is created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Administrator
 - Scheduler
 - Bookkeeper
 - Marketer

Lawn Care Worker
 - Entry Level
 - Experienced
 - Team Lead

Client
 - Residential
 - Commercial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In reality, these roles would be not be focused on the "who" and instead on the "what". For example, if the difference between residential and commercial as defined above is really about the difference in how the owner allows the client to pay, it would make more sense to have a "trusted_payer" permission, which allows the client to not have their credit card on file and be invoiced instead, etc. Then, when the owners favorite customer reads about credit card scams and asks to be invoiced rather than his card on file, that user's account can be meaningfully updated. Remember, a user can have multiple roles, it's not an either or. Permissions are just about "grouping" permissions for convenience and consistency! They're &lt;em&gt;not&lt;/em&gt; about creating fully descriptive categories. (Composition vs Category)&lt;/p&gt;

&lt;p&gt;The next type of user who will be logging in to our app is a &lt;em&gt;Homeowner Association Rep&lt;/em&gt;. They decide to create a role with limited permissions and allow the HOA members to see some of the metrics for this new source of income for the HOA.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Homeowner Association Rep
 - President
 - Member
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next type of user is a &lt;em&gt;Brand Rep&lt;/em&gt;. They log in to see ad metrics for their campaigns, and created a role with limited permissions for their intern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Brand Rep
 - Full
 - Intern
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last type of user is an &lt;em&gt;Internal Staff&lt;/em&gt; user. These are your and my employees, and they log in to see and configure data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Internal Staff
 - Superuser
 - Customer Support
 - Marketer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each of these roles under the six above profiles are specific to the "organization" that made them. In the case of the fist three profiles, those roles are part of the lawn care business's organization; for the HOA rep profile, the hoa organization; for the brand rep profile, the brand organization; and finally for our employers, an internal staff organization.&lt;/p&gt;

&lt;p&gt;This might sound odd, that these organizations aren't parallel. That's true if an organization includes the business or hoa or brand specific details, but our organizations do not. There would be a separate "business"/"hoa"/"brand" table for this data. An organization is just an entity used for permissions, and not coupled with a business, or hoa, or brand, or tenant, or conglomerate, or whatever-grouping-you-may-use.&lt;/p&gt;

&lt;p&gt;A user can perform the actions within an organization according to their roles (which are organization-aware).&lt;/p&gt;

&lt;p&gt;Lets say a user is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a client who uses both Tom's Lawn Care (for weekly mowing) and Jack's Landscaping (for less frequent landscaping tune-ups)&lt;/li&gt;
&lt;li&gt;the president of a Home Owner's Association, and use the affiliate referral program to raise money for their HOA (Blue Meadows)&lt;/li&gt;
&lt;li&gt;a marketing employee for our app company, using the staff app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This user account is associated with four different organizations: Tom's, Jack's, Blue Meadows, and Internal Staff. It is associated with three different profiles: client, homeowner association rep, and internal staff.&lt;/p&gt;

&lt;p&gt;When this user logs in, they are presented with their profiles. If they choose Internal Staff, they see can see metrics and data to better market our app. If they choose Homeowner Association Rep, they see a dashboard with their referral kickbacks. If they choose Client, they see the invoices from Tom and Jack, and since Jack has given them more permissions, for his they can see line items of his costs. One day, Tom gets spooked by the internet and removes all client permissions, and so only Jack's show up here.&lt;/p&gt;

&lt;p&gt;Thus, a user may have multiple profiles with multiple roles across multiple organizations - but our app code only cares about profiles, organizations, and permissions (not roles). If a &lt;/p&gt;

&lt;p&gt;It is important to note, roles within an organization within a profile "add up" - even if the permission is missing in one role in a profile, if it is present in another, the user has that permission.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example UIs
&lt;/h3&gt;

&lt;p&gt;Super rough demo example UI of permissions when a business owner is associating a new user with his organization:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjih89b8y4zp824i7mul.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnjih89b8y4zp824i7mul.png" alt="Permissions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Super rough demo example of a business owner adding a new role for his organization:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjqazzmp301qoyemucyz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxjqazzmp301qoyemucyz.png" alt="Add New Profile"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a user with more than one profile logs in, the app must enforce only allowing the user to act as one profile (and so making the user select which profile, or defaulting them to the last profile, etc).&lt;/p&gt;

&lt;h1&gt;
  
  
  Inspiration / Better Articles:
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://csrc.nist.gov/CSRC/media/Presentations/Role-based-Access-Control-an-Overview/images-media/alvarez.pdf" rel="noopener noreferrer"&gt;Role-Based Access Control&lt;/a&gt; by the National Institute of Standards and Technology&lt;br&gt;
&lt;a href="https://www.enterpriseready.io/square/role-based-access-control/" rel="noopener noreferrer"&gt;Role Based Access Control&lt;/a&gt; by Square&lt;br&gt;
&lt;a href="https://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/" rel="noopener noreferrer"&gt;Don’t Do Role-Based Authorization Checks; Do Activity-Based Checks&lt;/a&gt; by Derick Bailey&lt;/p&gt;

</description>
      <category>permissions</category>
      <category>authorization</category>
      <category>accesscontrol</category>
    </item>
  </channel>
</rss>
