在angularjs中为promise设置超时处理程序 [英] Setting a timeout handler on a promise in angularjs

查看:114
本文介绍了在angularjs中为promise设置超时处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的控制器中设置超时,以便如果在250ms内未收到响应,则应该失败。我已将我的单元测试设置为超时10000,以便满足此条件,任何人都可以指出我正确的方向吗? (编辑我试图在不使用我知道提供超时功能的$ http服务的情况下实现此目的)

I'm trying to set a timeout in my controller so that if a response isn't received in 250ms it should fail. I've set my unit test to have a timeout of 10000 so that this condition should be met,Can anyone point me in the right direction? ( EDIT I'm trying to achieve this without using the $http service which I know provides timeout functinality)

(编辑 - 我的其他单元测试失败因为我不是'对他们调用timeout.flush,现在我只需要在promiseService.getPromise()返回未定义的promise时获取超时消息。我已从问题中删除了早期代码。)

(EDIT - my other unit tests were failing because I wasn't calling timeout.flush on them, now I just need to get the timeout message kicking in when an undefined promise is returned by promiseService.getPromise(). I've removed the early code from the question) .

promiseService(promise是一个测试套件变量,允许我在申请之前对每个测试套件中的承诺使用不同的行为,例如拒绝一个,成功另一个)

promiseService (promise is a test suite variable allowing me to use different behaviour for the promise in each test suite before apply, eg reject in one, success in another)

    mockPromiseService = jasmine.createSpyObj('promiseService', ['getPromise']);
    mockPromiseService.getPromise.andCallFake( function() {
        promise = $q.defer();
        return promise.promise;
    })

正在测试的控制器功能 -

Controller function that's being tested -

$scope.qPromiseCall = function() {
    var timeoutdata = null;
    $timeout(function() {
        promise = promiseService.getPromise();
        promise.then(function (data) {
                timeoutdata = data;
                if (data == "promise success!") {
                    console.log("success");
                } else {
                    console.log("function failure");
                }
            }, function (error) {
                console.log("promise failure")
            }

        )
    }, 250).then(function (data) {
        if(typeof timeoutdata === "undefined" ) {
            console.log("Timed out")
        }
    },function( error ){
        console.log("timed out!");
    });
}

测试(通常我在这里解决或拒绝承诺,但不设置它我正在模拟超时)

Test (normally I resolve or reject the promise in here but by not setting it I'm simulating a timeout)

it('Timeout logs promise failure', function(){
    spyOn(console, 'log');
    scope.qPromiseCall();
    $timeout.flush(251);
    $rootScope.$apply();
    expect(console.log).toHaveBeenCalledWith("Timed out");
})


推荐答案

首先,我想说你的控制器实现应该是这样的:

First, I would like to say that your controller implementation should be something like this:

$scope.qPromiseCall = function() {

    var timeoutPromise = $timeout(function() {
      canceler.resolve(); //aborts the request when timed out
      console.log("Timed out");
    }, 250); //we set a timeout for 250ms and store the promise in order to be cancelled later if the data does not arrive within 250ms

    var canceler = $q.defer();
    $http.get("data.js", {timeout: canceler.promise} ).success(function(data){
      console.log(data);

      $timeout.cancel(timeoutPromise); //cancel the timer when we get a response within 250ms
    });
  }

您的测试:

it('Timeout occurs', function() {
    spyOn(console, 'log');
    $scope.qPromiseCall();
    $timeout.flush(251); //timeout occurs after 251ms
    //there is no http response to flush because we cancel the response in our code. Trying to  call $httpBackend.flush(); will throw an exception and fail the test
    $scope.$apply();
    expect(console.log).toHaveBeenCalledWith("Timed out");
  })

  it('Timeout does not occur', function() {
    spyOn(console, 'log');
    $scope.qPromiseCall();
    $timeout.flush(230); //set the timeout to occur after 230ms
    $httpBackend.flush(); //the response arrives before the timeout
    $scope.$apply();
    expect(console.log).not.toHaveBeenCalledWith("Timed out");
  })

DEMO

的另一个例子:promiseService.getPromise

app.factory("promiseService", function($q,$timeout,$http) {
  return {
    getPromise: function() {
      var timeoutPromise = $timeout(function() {
        console.log("Timed out");

        defer.reject("Timed out"); //reject the service in case of timeout
      }, 250);

      var defer = $q.defer();//in a real implementation, we would call an async function and 
                             // resolve the promise after the async function finishes

      $timeout(function(data){//simulating an asynch function. In your app, it could be
                              // $http or something else (this external service should be injected
                              //so that we can mock it in unit testing)
        $timeout.cancel(timeoutPromise); //cancel the timeout 

         defer.resolve(data);
      });

      return defer.promise;
    }
  };
});

app.controller('MainCtrl', function($scope, $timeout, promiseService) {

  $scope.qPromiseCall = function() {

    promiseService.getPromise().then(function(data) {
      console.log(data); 
    });//you could pass a second callback to handle error cases including timeout

  }
});

您的测试类似于上面的示例:

Your tests are similar to the above example:

it('Timeout occurs', function() {
    spyOn(console, 'log');
    spyOn($timeout, 'cancel');
    $scope.qPromiseCall();
    $timeout.flush(251); //set it to timeout
    $scope.$apply();
    expect(console.log).toHaveBeenCalledWith("Timed out");
  //expect($timeout.cancel).not.toHaveBeenCalled(); 
  //I also use $timeout to simulate in the code so I cannot check it here because the $timeout is flushed
  //In real app, it is a different service
  })

it('Timeout does not occur', function() {
    spyOn(console, 'log');
    spyOn($timeout, 'cancel');
    $scope.qPromiseCall();
    $timeout.flush(230);//not timeout
    $scope.$apply();
    expect(console.log).not.toHaveBeenCalledWith("Timed out");
    expect($timeout.cancel).toHaveBeenCalled(); //also need to check whether cancel is called
  })

DEMO

这篇关于在angularjs中为promise设置超时处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆