Wednesday, May 6, 2015

Understanding promise in javascript

Please reference https://promisesaplus.com/ for promise specification.

Usually for aync js request, onSuccess and onError callback parameter are required to handle the async result. Those callback parameters must be passed in when calling the async method as below in the callMyTask function.

function myAsyncTask(onSuccess, onError) {
   setTimeout(function(){
            i++;
            if (i < 3){
                onSuccess(i); 
            } else {
               onError("i is larger than 3"); 
            }
    }, 3000);
}

function callMyAsyncTask(){
    myAsyncTask(
       function(i){
           console.log("result is: "+ i);
       },
       function(error){
          console.log(error);
       });
}
Sometimes the callback method will invoke another async request, needs to provide another set of onSuccess and onError callback methods. And those nested callback methods all need to be provided when making the initial async request, and this makes the code hard to read and maintain


Promise can be used to solve the issue. The key difference between promise and tradition way of async method is, when using promise to invoke an async request, it does not need to provide the callback method immediately. Instead, the callback methods are provided on the returned promise object using then method. As showing in the below sample when calling myAsyncTaskWithPromise() within callAsyncTaskWithPromise method, there is no callback provided, the callback is specified later using then method, this looks like a synchronized request.


function myAsyncTaskWithPromise(){
     var promise = new Promise(function(resolve, reject) {
            
         setTimeout(function(){
            i++;
            if (i < 10){
                resolve(i); // we got data here, so resolve the Promise
            } else {
               reject(Error("i is larger thatn 3")); //reject
            }
         }, 3000);
          
      });
      return promise;

}

function callAsyncTaskWithPromise() {
      var prom = myAsyncTaskWithPromise();
      prom.then(function(data) {
            console.log('Promise fulfilled of larger than 10');
          },
          function(error) {
             console.log('Promise rejected.'+ error);
      });
}

More important, the then method must also return another promise, and then method can be called on this returned promise again to provide success and error callback function.

If then's success or error callback method returns a value, or an object, or void (i.e. not having a return value),  which is not a promise, then the returned value will be wrapped as a new premise, and immediately pass the new fulfilled promise to the chained next then method's success or error callback method.

However, if then's success or error callback returns a new promise,  the chained then's resolution methods will be delayed until the new promise is fulfilled or rejected later.


The then method can be chained as shown in the below sample on nestedProm object. The sample returns a new promise from the first promise's callback method.


function myNestedAsyncTaskWithPromise(){
     var promise = new Promise(function(resolve, reject) {
            
         setTimeout(function(){
            i++;
            if (i < 10){
                resolve(i); // we got data here, so resolve the Promise
            } else {
               reject(Error("i is larger than 10")); //reject
            }
         }, 3000);
          
      });
      return promise;

}

function callNestedAsyncTaskWithPromise() {
      var prom = myAsyncTaskWithPromise();

      var nestedProm = prom.then(function(data) {
            console.log("outer then callback called");
            return new Promise(function(resolve, reject){
                setTimeout(function(){
                     if (data <5){
                           resolve(data);
                     }
                     else{
                          reject(Error("data is large  than 5"));
                     }
                  }, 3000);
              });
          },
          function(error) {
             console.log('Outer promise rejected.'+ error);
      });

      nestedProm.then (function(data){
                 console.log('Nested promise fulfilled of larger than 5');
            },
            function(error){
                  console.log('Nested promise rejected.'+ error);
            });

}    

The whole html file are attached below

<!DOCTYPE HTML>

<html>

<head>

<meta http-equiv="X-UA-Compatible" content="IE=edge" />

<meta charset="UTF-8" />


<title>javascript test</title>
<script type="text/javascript" >
var i =0;

function myAsyncTask(onSuccess, onError) {
   setTimeout(function(){
            i++;
            if (i < 3){
                onSuccess(i); 
            } else {
               onError("i is larger than 3"); 
            }
    }, 3000);
}

function callMyAsyncTask(){
    myAsyncTask(
       function(i){
           console.log("result is: "+ i);
       },
       function(error){
          console.log(error);
       });
}

function myAsyncTaskWithPromise(){
     var promise = new Promise(function(resolve, reject) {
            
         setTimeout(function(){
            i++;
            if (i < 10){
                resolve(i); // we got data here, so resolve the Promise
            } else {
               reject(Error("i is larger thatn 3")); //reject
            }
         }, 3000);
          
      });
      return promise;

}

function callAsyncTaskWithPromise() {
      var prom = myAsyncTaskWithPromise();
      prom.then(function(data) {
            console.log('Promise fulfilled of larger than 10');
          },
          function(error) {
             console.log('Promise rejected.'+ error);
      });
}

function myNestedAsyncTaskWithPromise(){
     var promise = new Promise(function(resolve, reject) {
            
         setTimeout(function(){
            i++;
            if (i < 10){
                resolve(i); // we got data here, so resolve the Promise
            } else {
               reject(Error("i is larger than 10")); //reject
            }
         }, 3000);
          
      });
      return promise;

}

function callNestedAsyncTaskWithPromise() {
      var prom = myAsyncTaskWithPromise();

      var nestedProm = prom.then(function(data) {
            console.log("outer then callback called");
            return new Promise(function(resolve, reject){
                setTimeout(function(){
                     if (data <5){
                           resolve(data);
                     }
                     else{
                          reject(Error("data is large  than 5"));
                     }
                  }, 3000);
              });
          },
          function(error) {
             console.log('Outer promise rejected.'+ error);
      });

      nestedProm.then (function(data){
                 console.log('Nested promise fulfilled of larger than 5');
            },
            function(error){
                  console.log('Nested promise rejected.'+ error);
            });
}    

</script>
</head>

<body>
    <button id="test" onclick="callMyAsyncTask()">asyncTask</button>&nbsp;&nbsp;
    <button id="asyncpromist" onclick="callAsyncTaskWithPromise()">asyncpromist</button>&nbsp;&nbsp;
    <button id="asyncpromistNested" onclick="callNestedAsyncTaskWithPromise()">nestedasyncpromist</button>&nbsp;&nbsp;

</body>

</html>

No comments:

Post a Comment