Thinking with JS Promise and Promises

 

Here's a real life example of a quick design iteration that we went through with promises this week.

In AngularJS (but this applies to any JavaScript), we have a function that calls the server to do a long running process.

function longProcess() {
    // dataservice returns a promise and we return that to our caller.
    return dataservice.longservice();
}

As this could potentially take nearly a minute, we want to add a waiting dialog.

AngularJS UI provides a modal dialog service $modal

function longProcess() {
  // create dialog
  var dialog = $modal.open({ templateUrl: 'wait.html' });

  var promise = dataservice.longservice();

  promise.then(
    function(){
      // success
      dialog.close();
    },
    function() {
      // fail
      dialog.close();
    }
  );
  return promise;
}

 

This works great.
But sometimes, the dialog flashes past too fast!  While the user is still trying to read it, it disappears.

Before we run off into code, let's stop a do a bit of thinking.

What we need is to combine the original promise, with a second new timer promise (of say 5seconds).  When both the service call has finished and the timer is up, we will resolve the promises.

So in pseudo code, it'd look like:

var p1 = service();
var p2 = $q.timer(5000);
var all = $q.all([p1,p2]);
all.then( /* resolve */ );

Note: $q is AngularJS' lightweight implementation of a Promise/A library Q.  The pseudo-code assumption was that $q would provide a timer-based promise that detonates once time is up.  In reality, $q doesn't provide such a method.  But the $timeout service in AngularJS returns a promise for exactly this scenario.

 

function longProcess() {
  var dialog = $modal.open({ templateUrl: 'wait.html' });

  var p1 = dataservice.longservice();
  var p2 = $timeout(angular.noop, 5000);
  var arrayOfPromises = [p1, p2];
  var promises = $q.all(arrayOfPromises);
  promises.then(
    function(){
      // success
      dialog.close();
    },
    function() {
      // fail
      dialog.close();
    }
  );

  // returns a combined promise to our caller.
  return promises;
}

 

Summary

The dialog opens and shows wait.html - it closes when the service is complete and when the timer has hit 5 seconds.