JavaScript

JavaScript Coroutines: Introduction

Promises and generators are great but in coroutines they find their true utility – enabling single-depth routines to be created. This avoids the much discussed callback hell which plagues much of JavaScript development.

Cooperative Routines

A coroutine is fortunately one of those programming concepts that can be taken at their name. Which is to say that a coroutine is a COoperative ROUTINE . What does this mean? It means it is a routine that cooperates with another routine to get a job done.

Subroutines vs. Coroutines

A subroutine is a special case of a coroutine where there is a control flow or dependency relationship between the primary routine and the secondary routine. They cooperate but one initiates the other and the other runs to completion and then returns control flow back to the primary routine. The subroutine loses state at the conclusion of it’s invocation whereas the primary routine can keep state across repeated invocations of the subroutine.

Equal Partners

In the case of coroutines, each routine has more-or-less equal standing in the relationship. You can think of a coroutines as two workers who share the completion of a task. An allegory might be two carpenters working on a table with one specializing in joinery and the other in sawing and sanding. As the chair is produced they each perform a different type of work but keep passing the chair back and forth between them until the table is complete. As follows:

Time Carpenter A Carpenter B
0 Cut and sand legs and seat
1 Join legs to seat
2 Cut and sand back
3 Join back to seat

So this is an idealized definition and example, but what does one look like in real life JavaScript. Let’s use JavaScripts timeout() function and a generator to show two coroutines might work together. First let’s look at the more familiar time out function.

Use your imagination and pretend that this timeout function is doing some useful work that is long running and asynchronous such as connecting to a database, making a network call, or reading in some data from disk.

Generators + Promises = Coroutines (in JavaScript anyway)

This equation states something which is not true in a computer science sense, but is true in the context of JavaScript. At a language level we will need to combine generators with promises to get practical coroutines. Coroutines themselves often return promises and this is how they are implemented in the well regarded JavaScript library co.  Calling promisified code from your generator function allows you to create asynchronous code that reads like familiar synchronous code. So first lets look at a promise that is serving as the coroutine that we are going to call.

To run the examples you will need to run NodeJS 0.11 or higher with the --harmony  flag or run io.js.

Coroutine #1

This code is very straight forward. We simply create an function that will sleep for a random period of time and enclose it in a Bluebird promise. When the function wakes up it resolves the promise. We return the promise creation function via module.exports to follow the module pattern of JavaScript package management. Let’s now look at the other Coroutine:

Coroutine #2

In this second code block we initiate the sequence that will cause the two coroutines to work together. As the coroutine flows through flow control keeps passing between the first instigator()  function and the promise-based coroutines it creates and yields to. Let’s look at the output.

Output

As you can see execution flow is passed between the coroutines.

Is a Promise Really a Coroutine?

A likely use case for coroutines is leveraging them with promises to do things like connect and populate a database or read in a file using a promisified library. This is why I chose to use promises as the coroutine that the initial coroutine invoked. But are promises really coroutines?

This is a legitimate question. In my view any routine which passes execution back and forth can be considered a coroutine. However it seems less obvious then with the example provided above with the two carpenters who clearly have equal standing in the relationship. A promise in some ways seems more like a subroutine than a coroutine. This is partially because it is created and initiated by the instigator()  function and only performs one action. It feels less like a subroutine due to the communications mechanism and that it communicates via the yield statement.

As I mention below, I’d like to explore other coroutine algorithms further.

Next Steps

While I have written production code using the model shown above, I feel I have just scratched the surface of what is possible with JavaScript coroutines. Next steps for me include more complex code structures – perhaps three generators passing execution back and forth between to complete a larger task that is comprised of three discrete tasks that each need to complete work work in an incremental or iterative fashion.

Leave a Reply

Your email address will not be published. Required fields are marked *