<!DOCTYPE html>
<html>

  <head>
    <script data-require="jquery@1.9.1" data-semver="1.91" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <link data-require="bootstrap-css@*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
    <link data-require="bootstrap@*" data-semver="3.3.2" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
    <script data-require="bootstrap@*" data-semver="3.3.2" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>
    <h3>$.Deferred Promise and progress/then calbacks</h3>
    <button class="btn btn-default" id="add">Add promise</button>
    <br><br>
    <div class="bars">
      <!--promise progess bars here-->
    </div>

  </body>

</html>
$(document).ready(function($) {
    
    //available styles of the progress bars
    //see bootstrtap.css
    var pbStyles = ['progress-bar-info', 'progress-bar-warning', 'progress-bar-danger', 'progress-bar-success'];
    
    //here we create Deferred object and set its lifecycle events
    //based on random time frames within 1.5, 2.5, 4.5 and 5.5 seconds
    function AddPromise(){
      
      var dfd = $.Deferred();
      
      //we pass the JSON object with 2 properties: 
      //'progess' and 'status' as an update message

      setTimeout(function() {
          dfd.notify({"progess":"20%", "status" : "Only started"});
        }, (1500 + Math.floor(Math.random() * 500 )) );
  
      setTimeout(function() {
          dfd.notify({"progess":"40%", "status" : "Still working ..."});
        }, (2500 + Math.floor(Math.random() * 1000 )) );
        
          setTimeout(function() {
          dfd.notify({"progess":"80%", "status" : "Still working ..."});
        }, (4500 + Math.floor(Math.random() * 1000 )));
  
       setTimeout(function() {
          dfd.resolve({"status":"Finished"});
        }, (5500 + Math.floor(Math.random() * 1000 )) );

    return dfd.promise();
      
    }
    
    //here we create new progress bar DOM element and 
    //set Deferred object state updates to 
    function bindPromise(promiseObject){
      
      var uuid = (new Date()).getTime().toString().substr(5),
          selectedStyle = pbStyles[parseInt(Math.random()*pbStyles.length)],
          prTemplate = $('<div class="progress ' + selectedStyle +'" id="' + uuid + '">' + 
                        '<div class="progress-bar" role="progressbar" ' + 
                        'aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div></div>');
                        
          $('.bars').append(prTemplate);       
          
      
          $.when(promiseObject).progress(function (argument) {
          //when status is updated
          
             $(prTemplate).css({
                 width: argument.progess
             }).text(argument.progess);
             
           }).then(function (argument) {
          //when Promise is finally resolved
          
               $(prTemplate).css({
                   width: '100%'
               }).text('Completed!');
           });
      
    }
    
    $(document).on('click', '#add', (function(){
      bindPromise(AddPromise());
    })

});

/* Styles go here */

.progress-bar {
  text-align:center;
}