JavaScript Async - Promises, The Revealing Constructor Pattern
Written by Ian Elliot   
Monday, 11 December 2017
Article Index
JavaScript Async - Promises, The Revealing Constructor Pattern
The Promise Mechanism

There is something mysterious inside a Promise, object that is. 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 in its own right.

This is an extract from the newly published JavaScript Async: Events Callbacks, Promises & Async/Await 

Now Available as a Book:

 JavaScript Async

cover

You can buy it from: Amazon

Contents

  1. Modern JavaScript (Book Only)
  2. Events,Standard & Custom
  3. The Callback
      extract - The Callback & The Controller
  4. Custom Async - setTimeout, sendMessage & yield
      extract - Custom Async
      extract - Avoiding State With Yield 
  5. Worker Threads
      extract - Basic Worker ***NEW
      extract - Advanced Worker Threads 
  6. Consuming Promises 
  7. Producing Promises
      extract - The Revealing Constructor Pattern
     
    extract - Returning Promises
     
    extract - Composing Promises
  8. The Dispatch Queue
      extract - Microtasks
  9. Async & Await
      extract -  Basic Async & Await
      extract -  DoEvents & Microtasks
  10. Fetch, Cache & Service Worker
      extract - Fetch  
      extract - Cache
     
    extract -  Service Workers

The Problem With Promises

When we first began implementing Promises there was a big 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 code that was consuming the Promise using then and catch functions was unable to change the Promise's state.

That is:

only the code that created the Promise should be able to set the Promise's 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 the Promise had and so the 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 is 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 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 Promises standard both resolve and reject are private methods of the Promise object itself.

The Revealing Constructor Pattern

Promises use a modification on the standard way that constructors provide private methods called the revealing constructor pattern. You don’t need to understand how this works to consume or even produce Promises, but it isn’t difficult and it might well have other uses.

Like all JavaScript patterns once you have seen it, it seems more than obvious.

First let’s see how to create a private method – if you are sure you know how, skip to the next section.

A private method is one that is created as a closure when an object is created. This is the standard method for creating a private variable accessible from within an object, but not from outside. The only difference is that the variable references a function.

For example:

function myConstructor(){
  var private=0;
  this.myFunction=function(){
                     alert(private);
                  }
}

This is a constructor for an object with just one method, myFunction.

The important part is the variable called private. This is not part of the object because it isn't declared as a property of the object. so if you try:

var myObject=new myConstructor(); myObject.private=1;

you will see an error that private doesn't exist. However, as private is in scope when myFunction is declared, it is available to it as a closure. That is:

myObject.myFunction();

does display the value of private.

A private method uses the same mechanism with the small difference that the variable references a function – an inner function which is not a method of the object being constructed.

This is the mechanism that the JavaScript Promise uses to make resolve and reject private methods, but with some additional twists.

The private functions and variables are accessed by a function that is passed to the constructor.

Let’s see how this works.

Suppose you need to set a private variable to some value, but only when the constructor is used.

The simplest solution is:

function myClass(value){
  var myPrivateVar=value;
  this.myMethod=function(){
                   console.log(myPrivateVar);
                  }
}

Now you can create an instance using:

var myObject=new myClass(10);
myObject.myMethod();

The value of the private variable will be printed, i.e. 10, and this has been set when the constructor was used, but the variable cannot now be altered by code external to the object.

This seems simple enough, but if we push the idea just a little further it gets a little bit more difficult.

What happens if you want to pass a function in the constructor call that works with private members of the object being constructed? The function is intended to be executed by the constructor as the object is being created.

A first attempt might be something like:

function myClass(func) {
 var myPrivateVar = Math.random();
 var reveal = function (){
                           return myPrivateVar;
                         }
 func();
}

This creates a private variable set to a random value which can be discovered by accessing the private method reveal. The idea is that func is a function passed into the constructor and then executed which can make use of reveal to access the value.

If you try it out by passing it a function that tries to make use of reveal:

var myObject = new myClass(
         function () { console.log(reveal()); }
                );

you will see an error message generated when func is called saying the reveal is undefined.

The error here is obvious, reveal is not in scope for the function passed into the constructor. Which variables a function can access is determined by where the function is declared, not where it is used. The solution to the mistake is simple enough – pass the required private members as parameters to the function.

That is:

var myObject = new myClass(
        function (reveal) { console.log(reveal()); }
       );

Note now that the function needs to be called within the constructor with a parameter:

function myClass(func) {
  var myPrivateVar = Math.random();
  var reveal = function () { return myPrivateVar;};
  func(reveal);
}

Now it all works. The function passed to the constructor can call private functions as long as they are passed to it when the function is called.

The general principles are:

  • Local variables and hence inner functions within an object’s constructor are private to the constructor and the object it constructs.

  • The object gains access to these private variables by closure.

  • Private members can be accessed by the code that calls the constructor by passing parameters.

  • If the code that calls the constructor passes a function that is executed by the constructor, this cannot access the private variables because they were not in scope when the function was defined.

  • However, you can pass the private variables to the function as they are in scope when the constructor calls the function.

 Notice that you can just as well write:

var myObject = new myClass(
                  function (privateFunction) {
                   console.log(privateFunction());}
);

 

The name of the function is just a place holder for the first parameter passed. What the function actually is only becomes fixed when the constructor calls the function. That is when it does:

func(reveal);

This pattern is generally useful to allow external code restricted access to private functions within a constructor and of course it is how the Promise constructor allows you access to the resolve and reject functions.

coverasync



Last Updated ( Monday, 11 December 2017 )