Disclaimer: This article can be classified as a Monad Tutorial and therefore considered harmful. Proceed at own risk.
And because writing asynchronous code is tough, the test writer (me) avoids it and favors writing tests synchronously except when absolutely necessary. And sometimes they write a test synchronously even if the application actually behaves asynchronously. And often they get away with it, because the test passes. Until it doesn't. It may, for instance, pass on Chrome in 99% of the cases. But when you have a hundred test cases, that's not going to be enough.
And when something that used to be synchronous becomes asynchronous, shit will really hit the fan if the tests were sloppy. In my experience this happens quite often. For example, you add an AJAX call somewhere. Bang!
Mocha supports asynchronous testing for sure. You can use callback-style functions in your
its. When you need to perform a long sequence of (possibly asynchrous) operations, you may use a library such as zhain and you're a bit better off.
And when things get async, you will end up with code looking like this.
Not a very complex case yet, yet a Callback Hell is starting to form here.
What if, just what if, you could write it like this instead:
In this form, the asynchronous calls do not break the flow. You just indicate an asynchronous call with the arrow symbol
<- code="">. Nice?->
Shouldn't be too hard to implement a precompiler that would automatically convert this to the former callbacky form.
A New Abstraction
Quizz: What is the abstraction that allows the fancy syntax above to be applied not only to callbacks but to arbitrary constructs sharing a couple of common traits? Which programming language supports this syntax and automatically "desugars" it?
In this abstraction, you need a method for chaining things together. Using Haskell syntax, it would look like
chain :: M a -> (a -> M b) -> M b
But let's call it the
Anyway, the actual code might look like this:
And this would be automatically preprocessed into
To make this work, the asynchronous operations, like the object returned by
findElement, need a method named
We might implement it like here.
findElementmethod would change to
The only change here is that we wrap the returned function using Async.
Now, given we had this preprocessor, we should be able to use our fancy new syntax with asynchronous operations as long as they are wrapped using
Now what if we wanted to write a function
getTextthat simply calls
findElementand returns the element text by calling
It would look like this.
Ugly huh? Fancy syntax to the resque:
do Asyncpart here is to tell the preprocessor to use namely the
So the preprocessor would convert
Async.of(x). This means we have to implement an
Async. Like here.
But simply put, Monads are just things that support
chain. These functions have different names in different environments (
Oh, and I'm sure some of you know how to write compilers and stuff, so pls make this precompiler and ship it to me on Github.
... some time passes ...