Back to home

The Promise object

Full TUTORIAL on the 'Promise' object: starting from basics concepts to complete, advanced configuration of all the possible options.

This tutorial is splitted in sections. Each one devoted to a particular argument.

All the section that have 'buttons' have also an underline javascript code accessible keeping the browser in debug mode: F12, will help to locate the topic points..

Working with the 'Promise' object involves these concepts:

'ProgressBar': how it works.

The 'ProgressBar'


The progress bar is a model for the 'entity' at point '1)'. It exposes a function named: 'start', designed to be used by a 'Promise'. 'Start' accepts 2 callbacks: 'resolve', 'reject' to send back a 'messages' to the 'Promise' object.
'Resolve' accepts one parameter used by 'start' to send back data to the 'Promise' object.

The 'Progress bar' implements an asynchronous process that runs for a random amount of time and ends up with one state chosen randomly between 4 internal states.

Resolved Rejected Timeout Rejected Rejected (internal error)
'Timeout' and 'error' are internal to the 'ProgressBar'. From the outside, both are a rejection ('reject').

One example could be: A company (The 'Promise') calls you (the 'Start' function) for a mission, and gives you a smartphone (the callback 'resolve'). Your task is to buy some stuff. When done you must call back your company, notifying that you succeed (the message) and the price of stuffs (the data).

Once received a message ('resolve' xOr 'reject'), the 'Promise' is ready to call the methods listed at the introduction point 3).
'PromiseGUI' is the tool used by this page to give a graphical representation of the action taken by the 'Promise'.

'PromiseGUI':how it works.
The 'PromiseGUI' is a graphical interface and is a model for the 'entity' at introduction, point 3). In the real world the 'entity' at point '3)' is what you want to do, once the entity at introduction point 1) completed its task (successfully or not).
The 'PromiseGUI' exposes 4 functions, each one with a different graphical representation:


In the real world:

'Promise': for dummies.
Now we are ready to use the 'Promise' object in the easiest way: a very basic, yet complete, configuration of the 'Promise' using the features just described.
(try some shot and then hit F12 and take a look at the code, please.)
What missed here, is the exception management, and the 'ProgressBar' is configured to not throw any exception.

To properly control a 'Promise' it's important to know how it reacts to an exception. 'Promise' is a docile tool, the only real attention is needed during the instantiation: new Promise(function (resolve, reject) {...});

The next sections will analyze the effect of an exception occurring in different places.

Promise basics: dealing with exceptions.
Exception occurring during the instantiation of a new 'Promise'. It is in sync with the 'main flow', that means this exception can be caught by a 'try-catch' session. Asynchronous exception are 'silent'. That's why the calback 'reject' is provided.
(Hit F12 and take a look at the code, please.)
That means, your code could receive something different from what it expects. The 'signature' of 'resolve' & 'reject' accepts one parameter, of any kind. But, in case of an uncaught synchronous exception, 'Promise' will call (internally) 'reject', passing an 'Error' object.
Promise basics: dealing with exceptions.
The Exception occurs when 'resolve' or 'reject' are running.
(try some shot and then hit F12 and take a look at the code, please.)
The Exceptions in the functions 'resolve' & 'reject aren't so dramatic. Any uncaught exception force the 'Promise' to 'raise' the 'catched' 'event'. (using try-catch session is mainly an option).
Promise basics: dealing with exceptions.
The Exception occurs when running 'finally'
(try some shot and then hit F12 and take a look at the code, please.)

Regarding the function 'finally', an exception in it will redirect the flow to the function 'catch'.

An exception can occur also in the 'catch' function (why not?). To cope with this event, you can choose between two strategies:
* A 'try-catch' session.
* Chaining the exception to another 'catch' handler, but this... is another story :)


Now it's time to put things together...(When the going gets tough, the tough get going.)

'Promise': the revenge of dummies.
Again, a 'Promise' in the easiest way. This time fully configurated against every possible exception: practically unstoppable

Nothing so special has happened so far. What we have done with 'Promise' can be easily implemented by any developer.

Now it's time to show 'Promise' in all its glory.

In the following sections, there will be a 'Master-Promise' and many 'Promises'. The 'MasterPromise' will fail or succeed, based its own configuration and what happens to its promises.

Promise.all() - JavaScript | MDN
With the function 'Promise.all', the 'Master-Promise':
- resolves (is successful) only when all its 'promises' resolve.
- Rejects (fails) as soon any of the 'promises' rejects.
Note: When a 'ProgressBar' fails, only the associate 'PromiseGUI' shows the right state (become red) all the other 'PromiseGUI' remains in the pending state (dimmed).
Promise.all (extended).
In this case, the implementation of 'Promise.all' is a little bit more advanced than the previous, in 'section 4A'.
Every 'ProgressBar' is able to set the state (the color) of its own 'PromiseGUI'.

Now, when one of the 'ProgressBar' rejects, it is possible to show the 'state' of the other 'ProgressBar'.
(every graphical element is properly colored);
Promise.allSettled. (browser compatibility)
Promise.allSettled() - JavaScript | MDN
The function 'Promise.allSettled', waits till all the 'ProgressBars' complete (successfully or not). Then resolves.
('allSettled' rejects only if a 'catch' occurs.)
Promise.race() - JavaScript | MDN
The function 'race', 'resolve' (is successfull) as soon a 'ProgressBar' 'resolve'. 'reject' as soon any of the 'ProgressBar' 'rejects'.
Promise.any() - JavaScript | MDN
With 'Promise.any', the 'Master-Promise':
- resolves (is successful) as soon any of the 'promises' resolve.
- Rejects (fails) when all 'promises' rejects.
Note: Only the succeeding progressBar can set properly its own ProgressGUI. The other progressBars are not able to show its own state.
Promise.any (extended).
In this case, the implementation of 'Promise.any' is a little bit more advanced than the previous, in 'section 4D'.
Every 'ProgressBar' is able to set the state (the color) of its own 'PromiseGUI'.

Now, every 'Promise' that fullfils (resolves or rejects) it is able to set its own 'PromiseGUI.
(every graphical element is properly colored);
Promise synchronous.

Using 'async/await' a 'Promise' transforms an Asynchronous process in a Synchronous.
(This configuration does not need a 'Master-Promise' that controls the other 'Promises')

Now some, more in-depth, consideration regarding:
1) concurrency and threading
Starting from section 4A, a single 'Master-Promise' controls many, independent and simultaneous processes. This is not a problem under javascript.
In fact, although a 'Promise' is controlling any number of processes, the javascript engine works on a single thread, so there is only one process running in a given time. Hence, when a 'start' function gets its 'CPU Time slot', it has the time to set its state and then notifying 'Promise' without worrying if another process might leave it in an inappropriate condition.

Single thread a demonstration.
This section tries to demonstrate what it means to be a single thread. In this demonstration:
- the horizontal line is time.
- the time between 2 vertical segments is always 50 milliseconds.
- there are two processes: the red and the green
- each process takes a random amount of time to complete
- an iteration is when both processes begin
- the scheduled interval between two iterations can be one of {100, 150, 200, 250, 300} [ms]
- the red process begins always before the green process and can last even more than (interval/2) [ms]
- the green process is always scheduled (interval/2) [ms] after the red process

Note: The canvas tag is not supported in Internet Explorer 8 and earlier versions.

The example shows that, regardless of any time schedule, operated by 'setInterval', every job (the function 'process') is executed only after the previous is completed (Only when the interval of 'setInterval' is long enough, the schedule will be respected.)
In other words, since the javascript 'engine' works on a single thread it does not allow Concurrency.
(Two -or more- processes cannot run at the same time: red and green bars never overlap.)
ProgressBar Synchronous/Asynchronous.
'ProgessBar' can also run as a synchronous process. This session shows the different behavior, due to the fact that the javascript engine, runs on a single thread.

When 'ProgessBar' is synchronous, each item completes its job always in the same order, always after the previous 'ProgressBar' completes and the page freezes.

How this affects 'Promise'?

Promise.then Synchronous/Asynchronous.
A single "Promise" is completely indifferent whether the process it controls is synchronous or asynchronous.

Configuring a 'Master-Promise' is a 3 steps process.

// 1) creating the array of promises where each element is a 'Promise', controlling its own process:
var promises = [ new Promise(process1), new Promise(process2), ... , new Promise(processN)];

// 2) creating the masterPromise:
var masterPromise = Promise.all(promises);

// 3) Let the masterPromise doing its job.
  .then( ... )
  .finally( ... )
  .catch( ... );

the fact is: they must be consecutive, but not necessarily in the same function!
The constraint is, masterPromise must be created, at least, immediately before the first resolve/reject is called.

Promise.all three steps.
Another 'Promise.all', this time configurated following the previous note.

Promise.race three steps.
Another 'Promise.race', this time configurated following the previous note.

In both the previous sections:
- the 'Master-Promise' is instantiated immediately before the first 'resolve' is called.
- the button 'then' is enabled immediatly after the 'masterPromise' is created.
It is a little bit strange configuration, but it works!

What lesson did we get from session 7?

- 7A show that synchronous process stop the flow of code till they completed
- 7B & 7C show that 'Master-Promise' can't be created, after the synchronous processes it controls are complete.

Hence the process controlled by the 'Promise' MUST be asynchronous to be correctly managed!

To be a little bit more detailed, the 'Master-Promise' needs to be created before any of the resolve/reject are called. But, to create a 'Master-Promise', for example, using Promise.race(promises), we need to create the array of promises (the parameter of the function Promise.race)
To force the process controlled by each promise in promises to 'wait' till the 'Master-Promise' is correctly configured, we 'push' the process out of the current executing function, using setTimeout(start, 0);

that's all folks.

Hoping you enjoyed this page.

Bye :)