A Journey Through Asynchronous Coding

Glenn Crownover
4 min readNov 3, 2016

I recently published an article describing a tiny little utility I call Zousan.evaluate. This utility (its just a function really) transforms large deeply nested Promise/Then constructs into a declarative set of name/value/deps definitions.

But while I was writing that article, I had a thought about another way to demonstrate the power and simplicity of this little utility: through a series of examples.

So for my maiden post on Medium, I will walk you through a series of calls to Zousan.evaluate. By the end, you will understand the full scope and power it affords.

Note: Although I refer to this function as Zousan.evaluate, it is not dependent on the Zousan library. Zousan is just a Promise shim (a very fast one) . Zousan.evaluate works with native Promises or any Promises implementation.

Example 1

First, we simply use Zousan.evaluate to build an object with a two properties, username with a value of glenn. and score with a value of 45. These properties are accessed through the ob variable in the then handler.

Example 2

Next, let’s illustrate a bit more power in defining values. The username is defined as before, but now the score is set by the return value from a function. And finally newScore has a deps property with a single item “score”. This is the dependencies array, and since “score” is the name of an item in your evaluate list, it’s value is used to resolve this dependency — meaning the value for score will be passed into the double function. The newScore property in this case will be assigned a value of 90.

Example 3

Ok, so now we are finally seeing some utility. We have two functions that return a promise (i.e. they are asynchronous functions) and getFavorites requires a user object that is obtained via getUser. To do this effectively using a simple getUser(name).then(getFavorites)would have been simple enough — but at least we are starting to see how this works with asynchronous functions.

Any function that returns a promise waits until that promise is resolved before assigning. Therefore, the promise returned from getUser must resolve before it can be used as the dependency for getFavorites — just as you would expect.

Also notice that all values are available in the final ob that is passed to the then handler. If we had tried to simply do getUser(name).then(getFavorites)we would have lost our reference to the user object.

Example 4

In Example 3 above, notice how we call renderUserFavs upon the resolution of Zousan.evaluate. This work, but there is a better way. We could have simply made renderUserFavs another item in the evaluate list and had it be dependent upon “user” and “favs” to obtain the same effect in a more elegant, declarative and extendable way. Lets refactor that change in and add a renderUser call to help illustrate its benefits:

This looks cleaner and simpler than the example3 above, yet does even more — calling renderUser as well as renderUserFavs. It also illustrates that you don’t need a name field if you have no need to reference the item later.

What will the flow look like for this example?

When this is executed, the username property is immediately assigned “glenn” and the getUser function is immediately called with this username. Everything else waits.

When getUser returns with the user object getFavorites and renderUser are called simultaneously. Then when getFavorites resolves we are able to call renderUserFavs.

What would this look like using vanilla Promise/Then calls?

Not bad.

While its not particularly explicit in the dependencies of each call, it isn’t hard to follow and determine what those dependencies are. You may even prefer it written this way.

But you will see that this does not evolve well. And in real working situations it will need to scale beyond this simple scenario.

To illustrate, lets imagine that the renderUser function returns a promise that resolves to a userRenderer object that is needed to call renderUserFavs rather than the user object.

Example 5

First lets adapt our vanilla version to incorporate the change. Since renderUserFavs now depends on renderUser, we’ll need to move the whole getFavorites call inside the then handler for renderUser

Our code is creeping to the right… a telltale sign of the dreaded Promise Hell! Its getting harder to read and determine what is truly a dependency on what.

And perhaps most tragically, this will be slow. It is non-optimized. The call to getFavorites will wait for renderUser to resolve, which is unnecessary since it only depends on the user object.

The difference between calling two function in a series and calling them in parallel can be as much as a factor of 2 (twice as fast)! For UX, it is critical to maximize the speed in which you respond, making optimization here very important.

Lets see how comparatively easy it is to incorporate this change into the Zousan.evaluate version:

Notice how the Zousan.evaluate version is not getting more complicated as the demands increase. The list grows vertically, in a linear fashion. The dependencies of each item in the list is explicit, and that alone dictates the control flow. So this version will be optimized. The call to getFavorites will not wait for renderUser because the userRenderer is not in the list of dependencies for getFavorites.

How to Get — How to Use

As stated above, Zousan.evaluate works with any Promise A+ implementation, such as that which comes with all modern browsers and Node. The utility is only 42 lines in its entirety and is included below.

If you really want your app to perform blisteringly fast, you may want to use Zousan anyway as it is much faster than native promises and is only about 2k in size. And if you add the Zousan-Plus library you get Zousan.evaluate with it.

2019/06/27 Update: Changed all mentions of “eval” to “evaluate” per name change in utility.

--

--