Aishwarya
Aishwarya

Reputation: 49

Angular promise failure on timeout

I want my promise to fail if it fails to return a result within 300ms, in case of failure I want another promise to be called which would be executing a default function which has a smaller execution time.

What I've tried so far -

    $timeout(function(){
      GetAirMsg.get({mDate: $filter('date')($scope.realdateFrom,'ddMMyy'),
                mDateO: $filter('date')($scope.realdateFrom,'yyyyMMdd'),
                mDateD: $filter('date')($scope.realdateFrom,'dd-MMM-yyyy'),
                acode: $filter('uppercase')($scope.air),
                offset: offsetInt}).$promise.then(function(result){
                /* result evaluation */    
            });
      },300).then(function(data){

         console.log('Timed out! sorry!');
         /*execute another promise with shorter execution time */
         console.log('data : '+data);

      },function(error){

        //console.log('Timed out! sorry!');

    });

and the service is -

angular.module('example').factory('GetAirMsg',['$resource',function($resource){
return $resource(serverBaseUrl + '/getAirMsg/:mDate/:mDateO/:mDateD/:acode/:offset', 
        {mDate: '@mDate',mDateO: '@mDateO',mDateD: '@mDateD',acode: '@acode',offset: '@offset'}, {
            get: {method: 'GET', isArray: false}
        });
}])

The service GetAirMsg executes a query which takes up a lot of time for a few values, the query is as optimized as it can at the moment. So I would like a fallback to be available which returns only the basic information.

Problem faced now - The console always shows 'Timed out! sorry! data : undefined'. The request remains in the pending state for cases which don't return a value within that timeframe.

Upvotes: 2

Views: 694

Answers (3)

Syam Pillai
Syam Pillai

Reputation: 5217

The reason for showing that console is because the timeout function worked successfully and since timeout not returning any data, the data will be undefined

try this.

controller code:

$scope.isFirstCallSuccess = false;

$timeout(function(){
	GetAirMsg.get({
		mDate: $filter('date')($scope.realdateFrom,'ddMMyy'),
		mDateO: $filter('date')($scope.realdateFrom,'yyyyMMdd'),
		mDateD: $filter('date')($scope.realdateFrom,'dd-MMM-yyyy'),
		acode: $filter('uppercase')($scope.air),
		offset: offsetInt})
		.$promise
		.then(function(result){
		/* result evaluation */    
		$scope.isFirstCallSuccess = true; // updating only if call success
	}, ,function(error){
		// API call was failure even before the timeout
	});
},300).then(function(){
	if(!$scope.isFirstCallSuccess){
		//the call was failure. the value is still false
		/*execute another promise with shorter execution time */
		console.log('Timed out! sorry!');
	}

});

EDIT:

Method: create one more service to cancel promises. Use that service to cancel if it's not completed before timeout ends

service:

function cancel( promise ) {
//it will cancel the promise only the promise is still active
  if (promise) {
    promise.reject();
  }
}

controller:

$scope.gettingAirMsg = GetAirMsg.get({
    mDate: $filter('date')($scope.realdateFrom,'ddMMyy'),
    mDateO: $filter('date')($scope.realdateFrom,'yyyyMMdd'),
    mDateD: $filter('date')($scope.realdateFrom,'dd-MMM-yyyy'),
    acode: $filter('uppercase')($scope.air),
    offset: offsetInt})
    .$promise
    .then(function(result){
        //success
        }, ,function(error){

    });

 $timeout(function(){
   yourService.cancel($scope.gettingAirMsg) 
   //it will cancel the promise only the promise is still active
   // if the promise ends before 300ms the cancel call will not pass active promise
 },300)

Upvotes: 2

Syam Pillai
Syam Pillai

Reputation: 5217

The reason for showing that console is because the timeout function worked successfully and since timeout not returning any data, the data will be undefined

try this.

controller code:

$scope.isFirstCallSuccess = false;

$timeout(function(){
  GetAirMsg.get({
      mDate: $filter('date')($scope.realdateFrom,'ddMMyy'),
      mDateO: $filter('date')($scope.realdateFrom,'yyyyMMdd'),
      mDateD: $filter('date')($scope.realdateFrom,'dd-MMM-yyyy'),
      acode: $filter('uppercase')($scope.air),
      offset: offsetInt})
    .$promise
    .then(function(result){
    /* result evaluation */    
    $scope.isFirstCallSuccess = true; // updating only if call success
  },function(error){
    // API call was failure even before the timeout
  });
  },300).then(function(){
  if(!$scope.isFirstCallSuccess){
    //the call was failure. the value is still false
    /*execute another promise with shorter execution time */
    console.log('Timed out! sorry!');
  }

});

Upvotes: 2

Kursad Gulseven
Kursad Gulseven

Reputation: 2008

You may use timeout setting of $resource. See a sample usage here.

As an example for your code;

Service:

angular.module('example').factory('GetAirMsg',['$resource',function($resource){
return $resource(serverBaseUrl + '/getAirMsg/:mDate/:mDateO/:mDateD/:acode/:offset', 
        {mDate: '@mDate',mDateO: '@mDateO',mDateD: '@mDateD',acode: '@acode',offset: '@offset'}, {
            get: {method: 'GET', isArray: false, timeout: 300}
        });
}])

Controller:

GetAirMsg.get({mDate: $filter('date')($scope.realdateFrom,'ddMMyy'),
        mDateO: $filter('date')($scope.realdateFrom,'yyyyMMdd'),
        mDateD: $filter('date')($scope.realdateFrom,'dd-MMM-yyyy'),
        acode: $filter('uppercase')($scope.air),
        offset: offsetInt}).$promise
    .then(function(result){
        /* result evaluation */    
    })
    .catch(function() {
        console.log("error!");
    });

Upvotes: 2

Related Questions