Montag, 30. Januar 2012

webOS: Implementing promises with Enyo components

I recently needed to make a few web service calls from within my Enyo application. I wanted to use the cujojs.com when.js library for synchronization with promises. Promises in itself are a very intriguing concept and I will write another blog post about them in the future.

In essence a promise works this way:

webservice.login(username, password).then(
  function loginSuccess(response) {
    enyo.log("Login successful");
  }, function loginFailed(response) {
    enyo.log("Login failed.");
  }); 

The login function of the web service sends out an request asynchronously and returns immediately. The usual way to handle this kind of behavior is to pass a set of callback functions to the login method, that are called when the service is successful or had failed. Promises allow for more compact code. See this article for a good explanation.

To make a web service call in Enyo you normally use an enyo.WebService component like this:

enyo.kind({
  name : "LoginComponent",
  kind : enyo.Component,
  components : [ {
    kind : "WebService",
    name : "loginWebService",
    url : "https://<your service URL here>",
    method : "post",
    onSuccess : "loginSuccess",
    onFailure : "loginFailure"
  } ],

  loginSuccess : function(inSender, inResponse, inRequest) {
    enyo.log("Login successful.");
  },

  loginFailure : function(inSender, inResponse, inRequest) {
    enyo.log("Login failed.");
  }
});

The WebService kind has to event methods onSuccess and onFailure. But in the definition of the kind, those two events take only strings. When the doSuccess or doFailure methods are called the intelligence of the enyo.Object handle the translation from the string to the actual method call.

To implement the promise concept with the WebService kind, we have to create our own kind.

enyo.kind({
  name : "LoginWebservice",
  kind : enyo.Component,
  
  deferred : undefined,
  
  components : [ {
    kind : "WebService",
    name : "loginWebService",
    url : "https://<your service URL here>",
    method : "post",
    onSuccess : "loginSuccess",
    onFailure : "loginFailure"
  } ],

  login : function(inUsername, inPassword) {
    this.deferred = when.defer();
    var params = {
      Username : inUsername,
      Password : inPassword
    };
    this.$.loginWebService.call(params);
    return this.deferred.promise;
  },

  loginSuccess : function(inSender, inResponse, inRequest) {
    this.deferred.resolve(inResponse);
  },

  loginFailure : function(inSender, inResponse, inRequest) {
    this.deferred.reject(inResponse);
  }
});

The component creates a deferred object and resolves/rejects it based upon the result of the web service call. Use the following code to integrate the kind in your own software:

enyo.kind({
  name : "LoginWebServiceTest",
  kind : "Component",
  components : [ {
    kind : "LoginWebservice",
    name: "wsLogin"
  }, {
    kind : "Button", 
    onclick: "loginTest"
  } ],

  loginTest : function(inSender) {
    this.$.wsLogin.login("Username", "MySecretPassword").then(
      function loginSuccess(response) {
        enyo.log("Login successful");
      }, function loginFailed(response) {
        enyo.log("Login failed.");
      }
    ); 
  }
});

x

Keine Kommentare:

Kommentar veröffentlichen