Promises

A promise is a placeholder for the return value of an operation that has been called asynchronously. It enables you to specify subsequent actions to be performed with that value when it is eventually received.

Promises enable you to easily and consistently handle asynchronous activation of server-side and client-side code. They make code more understandable because they do not required the server-side and client-side code to mutually call each other.

Promises are part of the next ECMAScript standard, and make it easier to chain actions and handle errors. Uniface promises are compliant with the Promises/A+ specification. For more information on Promises/A+ and the draft ECMAScript standard, see the following web sites: https://promisesaplus.com/ and ECMAScript® 2015 Language Specification: Promise Objects. There is, of course, much more information available on the web on how you can use promises.

The Uniface JavaScript API supports the use of promises for the createInstance(), activate(), and all the uniface.datastore functions. These functions return JavaScript promise objects.

To handle a promise, use the then method as part of the call to the function. For example:

ComponentInstance.activate({OperationName{,Parameters}).then(PromiseFullfilledAction, PromiseRejectedAction);

Understanding Promises

To better understand how to use promises and the advantages promises have, assume you have a DSP in which we want to display the coordinates of an address on a map. To do this, the client-side JavaScript code calls a server-side operation that returns the address coordinates, which are then used to update a Google map.

Without Promises

To implement this functionality without promises, the following code is required:

; Detail trigger of a field
webtrigger onClick
  javascript
    window.address = getAddress();
    uniface.activate("lookupcoordinates", address) Callout 1
  endjavascript
end
; Operations container of the component
operation lookupcoordinates
  public web
  params
    string address: in
  endparams

  call CalcCoordinates(LATITUDE.C.LOCATION, LONGITUDE.C.LOCATION) and Callout 2
  webactivate $instancename.updatemap() Callout 3
end

weboperation updatemap Callout 4
  javascript
    var occ = uniface.getEntity("C.LOCATION").getOccurrence(0);
    google.maps.locate(occ.getField("LATITUDE").getValue(), 
                       occ.getField("LONGITUDE").getValue(),
                       window.address);
  endjavascript
end
  1.  The onClick trigger of a field calls a server-side operation called lookupcoordinates.
  2.  The operation lookupcoordinates calculates the coordinates of an address.
  3.  It then calls a web operation called updatemap. This is a callback to the client-side code, and therefore assumes that the lookupcoordinates operation can only be called from browser and never by server-side code.
  4.  The updatemap web operation sets the address coordinates on a Google map.

There are several issues with this code:

  • The server-side operation lookupcoordinates is closely intertwined with what the client wants to do with the result. It must call the appropriate operation on the browser. This is not information that should be handled at this level and means that the operation cannot be called by other operations or components.
  • If the lookupcoordinates operation call fails, there is no feedback to the user.
  • If the originating trigger needs to share state with the callback operation, it needs to go via a global variable.
  • The code is convoluted and hard to follow.
With Promises

The Uniface JavaScript API supports the use of promises for the createInstance() and activate() functions. These functions return JavaScript promise objects.

To handle the promise returned by the activate() function, you can use the following code:

; onClcick trigger of a field
webtrigger onClick
  javascript
    var address = getAddress();
    uniface.activate("lookupcoordinates"Callout 2.1, address).then(Callout 2.2
      function()Callout 2.3 {var occ = uniface.getEntity("C.LOCATION").getOccurrence(0);
                  google.maps.locate(occ.getField("LATITUDE").getValue(), 
                  occ.getField("LONGITUDE").getValue(),
                  address);
                 }, 
      function(e)Callout 2.4{ alert("lookup failed"); });
  endjavascript
end
; Operations container of the component
operation lookupcoordinates Callout 2.5
  public web
  params
    string address: in
  endparams

  call CalcCoordinates(LATITUDE.C.LOCATION, LONGITUDE.C.LOCATION)

end
  1.  The onClick trigger of a field calls a server-side operation called lookupcoordinates.
  2.  The then method handles the promise. It specifies what to do if the promise is fullfilled (the action succeeded) and what to do if it is rejected (the action relating to the promise failed).
  3.  If the promise is fulfilled, it resolves to a value, which can be used in a subsequent action, in this case to update the Google map.
  4.  If the promise is rejected, an error object is returned, and an error message is displayed.
  5.  The operation lookupcoordinates calculates the coordinates of an address. It does not need to know anything about how it was called.

Related Topics