JavaScript Jems - The Revealing Constructor Pattern
Written by Mike James   
Tuesday, 18 March 2025
Article Index
JavaScript Jems - The Revealing Constructor Pattern
Private Methods
The Revealing Constructor

JavaScript should not be judged as if it was a poor version of the other popular languages - it isn't a Java or a C++ clone. It does things its own way and sometime it can do unexpectedly clever things like the revealing constructor.

This is an extract from JavaScript Jems: The Amazing Parts.

Jem 15

The Revealing Constructor Pattern

Those that are most slow in making a promise are the most faithful in the performance of it.”

Jean-Jacques Rousseau

Now available as a book from your local Amazon.

JavaScript Jems:
The Amazing Parts

kindlecover

Contents

<ASIN:1871962579>

<ASIN:1871962560>

<ASIN:1871962501>

<ASIN:1871962528>

 

There is no doubt that the Promise is a JavaScript jem. Other languages have Promises or something similar, but the JavaScript way of doing the job is amazing. We have just looked at the Promise along with async/await, but there is something more to learn by understand how Promises are implemented. There is something mysterious inside a Promise object that could well have other applications if it was better known.

You may think that you have Promises mastered, but do you really know how they work? The whole security of the Promise is based on the revealing constructor pattern, which is useful and a jem in its own right.

The idea of a Promise object is a clever one, but to implement it properly requires even more cleverness. Early attempts at creating a Promise were flawed and it took time to work out how to do it properly. The fact that is can be done properly without having to change JavaScript is an affirmation that JavaScript as a whole is a jem, but only if you understand it well enough.

Creating Promises

When you create a standard Promise you use its constructor and you pass it a single function, the executor, that is immediately executed by the constructor, for example:

let p=new Promise(executor);

The executor is the function where you create the asynchronous task and then call the Promise's resolve or reject methods accordingly – usually when the asynchronous task has completed. In other words, this is the code that does the work that you are interested in.

For example, the delay function introduced in Jem 14 can be written using JavaScript Promises as:

function delay(t) {
  var p = new Promise( 
               function (resolve, reject) {
                 setTimeout(                     function () {                          resolve();                      },                  t);                });
  return p; }

You can see that this follows the pattern, creating a Promise by passing its constructor an executor function with resolve and reject as parameters. The executor function does what it has to do to complete the function’s task and arranges to call ether resolve or reject according to whether or not the task is successfully completed. The constructor executes the executor immediately and it is important that the executor returns as quickly as possible. In the example, the executor sets up an asynchronous action, i.e. it calls setTimeout, and then returns. It is only much later, after t milliseconds, that the function specified in the setTimeout is executed and this calls resolve or reject. Notice that you supplied the executor function but resolve and reject are functions that are defined within the Promise

It is important that the functions resolve and reject are private to the Promise and only it and the executor have access to them. When we first began implementing Promises keeping them private was a problem. It was essential to provide functions so that the code that was using the Promise to signal when it was finished could change the state of the Promise, but the code that was consuming the Promise, using then and catch functions, was unable to change the state of the Promise.

That is, only the code that created the Promise should be able to set its state.

The earliest solution to this problem of keeping the internal state private was to use a two-object solution. This is the solution that jQuery adopted in the very early days of Promises and it is a lesson in why it is not always good to be a first adopter. jQuery uses two similar objects, the Deferred and the Promise to implement a standard Promise.

A Deferred object was used by the Promise creator to manage the Promise. The Deferred had the necessary functions to resolve and reject the Promise, and the Promise had all of the functions the consumer needed, like then.
In practice, it was better to have the Deferred object also having all of the functions that Promise had and so Deferred looked like a "super-Promise" object. The Deferred object was kept private to the object that created the Promise, and was used by it to call resolve and reject methods that place the Promise in the resolved or reject state.

In retrospect this was probably a mistake as it results in a confusion between what the Deferred is, and what it is used for. If you wanted to, you could pass the Deferred object to the user rather than the Promise object and this would allow them to change the internal state.

The two-object solution to keeping the resolve and reject functions private was solved by the generalization of the mechanism long used to keep methods and properties private to an object. That is, in place of a private Deferred object which has the accept and reject methods, in the Promise’s standard both resolve and reject are private methods of the Promise object itself.

This all works but there is a better way.



Last Updated ( Tuesday, 18 March 2025 )