Blocking and non-blocking functions
- Declarations and assignments of variables;
- Definitions of functions;
- Increment, decrement and delete operations;
- Control structures (conditionals, loops and jumps);
- Calls or invocations of blocking functions;
- Calls or invocations of non-blocking functions.
A blocking function, just like a non-blocking function, takes in one or several inputs and performs one or several tasks. We usually expect a function, blocking or non-blocking, to deliver a useful result in some way. This result is meant to be reused later in our program. But this point is exactly what separates blocking functions from non-blocking ones: how easy is it to get that useful result?
Blocking functions are straightforward in that regard. They return a value that can be assigned to a variable and reused later on, in a different scope from the blocking function's one.
Non-blocking functions are trickier. They do not and they cannot return a value that can be "directly" useable or stored in a variable. The important word here is directly. Also, there are 2 types of non-blocking functions that are quite different, regarding how "directly" the useful value can be used.
Callback-based non-blocking functions use a callback function to be able to execute some code after a non-blocking task is completed.
These functions do not and cannot return a value.
There is no way to store a useful result in a variable for later use.
If you try to do so, the variable will be assigned the value
undefined, since the function does not and cannot return an explicit value. Moreover, if you have several tasks to execute after a non-blocking task is completed, you have to nest several callbacks within one another, inside the function. This problem is called callback hell or the Christmas tree problem, and it produces ugly and, most importantly, hard-to-maintain code.
Promise-based non-blocking functions use special objects called Promises, that were introduced in the ES6/ES2015 specification.
Promises address the disadvantages of callback-based non-blocking functions in a very clean way.
First, Promise-based non-blocking functions can and should return a value, in the form of a Promise object.
This object is complex: it has a state that changes through time. Regardless, it is an object that can be stored in a variable.
It can be reused later on, almost like any variable that stores the return value of a blocking function.
Almost, because performing a task after a Promise settles (by resolving a value or rejecting a reason for failing) requires using either the
then()method, either the syntactic sugar keywords
awaitwith a function.
The key to writing clean non-blocking code is to make sure that non-blocking functions always return Promises. If a non-blocking function is not available in its Promise-based version, you can create it: this is called to "promisify" a function.
Initial publication date: