Every programmer who starts developing under Node.js faces the choice of a strategy for organizing asynchronous code in a project. While in small system utilities, it is quite simple to maintain the hygiene of an asynchronous code, with the increase in the mass of the code in a project, the solution of this problem begins to require the introduction of an additional, so-called
control flow .
This article will discuss the small control flow library
“Flowy” , which is the development of
Step Step Caswell's ideas of the project, and the core of which is based on
CommonJS Promises concepts, and also gives arguments why Promises is so inconvenient.

')
What it looks like
function leaveMessage(username, text, callback) { Flowy( function() {
- Each step passed to the
Flowy
wrapper Flowy
executed in the context of the library ( this
variable). At the same time, the context provides the ability to transfer data to the next step by generating callbacks that can be passed to the classical nodejs-like functions as the last argument (call this.slot()
). - Everything that is performed in one step is performed in parallel.
- The control will be transferred to the next step only after all its “slots” are filled with data - all callbacks generated by the call to
this.slot()
completed successfully, or the first one will receive an error message. - If an error occurs in any of the steps, the execution of the entire chain will be interrupted and the error will be returned to the last step.
Why does it look that way?
A beginner acquaintance with the API of the non-blocking I / O Node.js system is offered the following asynchronous call interface:
fs.readFile('/etc/passwd', 'utf8', function (err, data) { if (err) throw err; console.log(data); });
When using someone else’s modules, it’s natural to want to have an interface similar to that described above — the
rule of least surprise is one of the keys to supporting and easily debugging code. From here comes the first requirement for the library:
We want to keep the “native” nodejs-like interfaces of functions and callbacks. Each step of
Flowy
has a nodejs callback interface, which makes it easy to wrap the entire chain of steps into a traditional nodejs function.
In this case, the main idea of ​​Promises (as an example of the implementation will be used in the future library
"Q" by Chris Cowell) is to replace the callback transfer with the last argument to the asynchronous call by creating a chain of calls to the Promise methods:
The first thing that catches your eye: functions
return Promise . Thus, to use the library, it is necessary to wrap all the “classic” functions in the Promise adapter (this process is described in more detail on the project's page), or else to
develop code with interfaces that are strictly library-oriented (however, all public interfaces of the module will need to be returned classic view, given the requirement formulated above). It is not comfortable. It sounds scary and no less scary. At the same time, the second requirement for the control flow library immediately comes to mind:
The library should be only a “glue” between the existing parts of the system and not become a heavy dependency. All the features of “Flowy” functioning are hidden inside the steps - that same glue - which allows functions using it to remain “clean” for the outside world. Soar should remain in the hut.
When working with libraries that allow you to create chains (chaining) of asynchronous calls, it is often necessary to perform part of the calls
in parallel . The Q library provides the following
awkward solution:
Q.allResolved(promises) .then(function (promises) { promises.forEach(function (promise) { if (promise.isFulfilled()) { var value = promise.valueOf(); } else { var exception = promise.valueOf().exception; } }) })
In addition to everything, if we suddenly want to break the rule “one argument - one return value”, then we will have to do additional exercises:
return getUsername() .then(function (username) { return [username, getUser(username)]; }) .spread(function (username, user) { })
Reading this code, one more requirement to the library suggests itself:
We want to easily execute several parallel queries and pass any number of arguments to callbacks. “Flowy” is able without any additional effort on the part of the developer due to its architecture.
So, “Flowy” is a lightweight library for managing the asynchronous flow of program execution, which makes it easy to solve everyday issues of developers under Node.js and has proven itself in the production environment.
This article demonstrates only the basic features of “Flowy”. For more information, I invite everyone to visit the project page on the githaba, where you will find abundant documentation with many examples.
Useful sources: