Sitemap

Asynchronous Locks in Modern Javascript

2 min readMar 19, 2018

--

The problem

Because everybody is raving about concurrency these days, it’s funny that one of the hardest things to do in Javascript (and in any language I know) is still to write consecutive code — not synchronous, but consecutive.

When async/await reached Node and the major browsers, I was relieved. It flattened the infamous pyramid of doom even further than bare Promises ever did, and the event-based nature of the language didn’t seem like a square wheel anymore. Turns out that with a little twist, it can also solve the problem of sequentiality (waiting for things before doing things).

Let’s say you have an asynchronous function streamToFile(data) that receives a big amount of data and streams it to a file. Horrible things will happen if that function is called while one instance is still running, so you want to wait for the first call to finish. Here’s the thing: you don’t want to lose the data associated with the second call, so you make a queue. When the function finishes, you make it check the queue for pending calls, and call the function again with its respective data. That works.

Get Christophe Marois’s stories in your inbox

Join Medium for free to get updates from this writer.

But what if you want to wait for the call itself to finish before doing something else, like this?

If there is another instance of streamToFile() running, how can you wait for this particular call to end before doing reportDone()? With the Queue design pattern, it’s very complex to do. How, then, can we: 1. wait for existing calls to finish; and 2. wait for our current call to finish; before 3. doing something else?

The solution

Asynchronous Locks are a design I’ve used extensively in a variety of situations in the past months. They are really easy to implement and solve the aforementioned problem easily:

With this pattern, we can rewrite our streamToFile(data) function like this:

That way, any call to the function will be “buffered”, making the calls consecutive, while still being await-able.

How it works

The Asynchronous Lock pattern relies on somewhat of a “promise hack”. It creates a Promise and stores its resolve() function outside of its scope, effectively making an infinite Promise that is resolvable from the outside. That way, we can await the lock before doing something, manually controlling our asynchronous flow.

Conclusion

Async/await is a wonderful thing, and enables a variety of new design patterns that were very hard to do before.

If you cannot live without async/await, be sure to also check Awaity, a utility library that enables functional methods like map() to be easily used with the syntax.

What are your favorite tricks?

--

--

Christophe Marois
Christophe Marois

Written by Christophe Marois

Classical music graduate and web developer. Over a thousand patents refused.