Angularjs如何在切换路由时取消资源承诺

Angularjs如何在切换路由时取消资源承诺,angularjs,Angularjs,我刚被Angularjs弄湿了脚。我有一个问题,我认为与承诺有关 假设我加载了路由“A”,它通过其控制器发出几个ajax请求: allSites = AllSites.query({ id:categoryID }); allSites.$promise.then(function(allSites){ //add stuff to the scope and does other things //(including making another ajax request

我刚被Angularjs弄湿了脚。我有一个问题,我认为与承诺有关

假设我加载了路由“A”,它通过其控制器发出几个ajax请求:

allSites = AllSites.query({ id:categoryID });

allSites.$promise.then(function(allSites){
    //add stuff to the scope and does other things 
    //(including making another ajax request)
});
$scope.categories = Category.query();
然后我有路由“B”,它通过控制器发出自己的API请求:

allSites = AllSites.query({ id:categoryID });

allSites.$promise.then(function(allSites){
    //add stuff to the scope and does other things 
    //(including making another ajax request)
});
$scope.categories = Category.query();
以下是路线“A”当前使用的工厂服务:

.factory('AllSites',function($resource){
    return $resource('api/categorySites/:id');
});
当我第一次查看路由“A”,但在“A”完成加载之前切换到“B”时,路由“B”会坐在那里等待“A”中最初请求的所有内容完成(实际上,query()请求已发出,但在“A”中的请求完成之前,它不会解析。然后()继续发生,尽管我不需要它,因为我现在在另一条路线上

正如您在我的devtools时间线中所看到的,绿线表示我何时切换到路由“B”。路由“B”的请求直到上述两个请求解决后才得到解决(请求通常非常快)。(此时,我可以作为用户使用视图)。然后,从路由“a”解决更多承诺

我到处寻找答案,只能找到那些想“推迟”路线装载直到承诺得到解决的人。但在我的情况下,我几乎想要相反的结果。我想在切换时终止这些请求

这是另一个人提出的同样的、未回答的问题:

非常感谢您的帮助。

请看

你可以做他正在做的事情,并解决在路由更改(或状态更改,如果使用ui路由器)时中止请求的承诺


这可能不是最容易实现的事情,但似乎它可以工作。

首先,我决定使用
$http
,因为我找不到任何使用
$resource
的解决方案,也无法让它单独工作

根据@Sid的回答,我的工厂变成了这样,使用

然后,在我的控制器中(从我的问题路由“A”):


我希望工厂不要那么混乱,但我会尽我所能。然而,现在有一个单独的相关问题,虽然承诺被取消,但下一步行动仍然被推迟。如果你对此有答案,你可以将其张贴在那里。

有一个类似的问题,答案为“”

虽然它没有准确地解决这个问题,但它提供了在切换路由时取消资源请求的所有要素:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Cancel resource</title>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular-resource.js"></script>
  <script>
angular.module("app", ["ngResource"]).
factory(
  "services",
  ["$resource", function($resource)
  {
    function resolveAction(resolve)
    {
      if (this.params)
      {
        this.timeout = this.params.timeout;
        this.params.timeout = null;
      }

      this.then = null;
      resolve(this);
    }

    return $resource(
      "http://md5.jsontest.com/",
      {},
      {
        MD5:
        {
          method: "GET",
          params: { text: null },
          then: resolveAction
        },
      });
  }]).
controller(
  "Test",
  ["services", "$q", "$timeout", function(services, $q, $timeout)
  {
    this.value = "Sample text";
    this.requestTimeout = 100;

    this.call = function()
    {
      var self = this;

      self.result = services.MD5(
      {
        text: self.value,
        timeout: $q(function(resolve)
        {
          $timeout(resolve, self.requestTimeout);
        })
      });
    }
  }]);
  </script>
</head>
<body ng-app="app" ng-controller="Test as test">
  <label>Text: <input type="text" ng-model="test.value" /></label><br/>
  <label>Timeout: <input type="text" ng-model="test.requestTimeout" /></label><br/>
  <input type="button" value="call" ng-click="test.call()"/>
  <div ng-bind="test.result.md5"></div>
</body>
</html>

取消资源
angular.module(“应用程序”、[“ngResource”])。
工厂(
“服务”,
[“$resource”,函数($resource)
{
函数resolveAction(解析)
{
if(this.params)
{
this.timeout=this.params.timeout;
this.params.timeout=null;
}
this.then=null;
解决(这个问题);
}
返回$resource(
"http://md5.jsontest.com/",
{},
{
MD5:
{
方法:“获取”,
参数:{text:null},
然后:解决行动
},
});
}]).
控制器(
“测试”,
[“服务”、“$q”、“$timeout”、函数(服务、$q、$timeout)
{
this.value=“示例文本”;
this.requestTimeout=100;
this.call=函数()
{
var self=这个;
self.result=services.MD5(
{
文本:自我价值,
超时:$q(函数(解析)
{
$timeout(解析,self.requestTimeout);
})
});
}
}]);
文本:
超时:
工作原理
  • $resource合并操作定义、请求参数和数据,为$http请求生成配置参数
  • 传递到$http请求中的配置参数被视为类似承诺的对象,因此它可能包含初始化配置的then函数
  • 操作的then函数可以将超时承诺从参数传递到配置中

  • 请查看“”了解详细信息。

    我用$q.reject()取消了承诺。我认为这种方式更简单:

    在SitesServices.js中:

    ;(() => {
      app.services('SitesServices', sitesServices)
      sitesServices.$inject = ['$http', '$q']
      function sitesServices($http, $q) {
    
        var sitesPromise = $q.defer()
        this.getSites = () => {
          var url = 'api/sites'
          sitesPromise.reject()
          sitesPromise = $q.defer()
          $http.get(url)
            .success(sitesPromise.resolve)
            .error(sitesPromise.reject)
    
          return sitesPromise.promise
        }
      }
    })()
    
    ;(() => {
      app.controller('SitesController', sitesControler)
      sitesControler.$inject = ['$scope', 'SitesServices']
      function sitesControler($scope, SitesServices) {
        $scope.sites = []
    
        $scope.getSites = () => {
          SitesServices.getSites().then(sites => {
            $scope.sites = sites
          })
        }
      }
    })()
    
    在SitesController.js中:

    ;(() => {
      app.services('SitesServices', sitesServices)
      sitesServices.$inject = ['$http', '$q']
      function sitesServices($http, $q) {
    
        var sitesPromise = $q.defer()
        this.getSites = () => {
          var url = 'api/sites'
          sitesPromise.reject()
          sitesPromise = $q.defer()
          $http.get(url)
            .success(sitesPromise.resolve)
            .error(sitesPromise.reject)
    
          return sitesPromise.promise
        }
      }
    })()
    
    ;(() => {
      app.controller('SitesController', sitesControler)
      sitesControler.$inject = ['$scope', 'SitesServices']
      function sitesControler($scope, SitesServices) {
        $scope.sites = []
    
        $scope.getSites = () => {
          SitesServices.getSites().then(sites => {
            $scope.sites = sites
          })
        }
      }
    })()
    

    查看文档中的
    $resource
    我发现了一个指向这个小美女的链接。 $http#使用率

    超时–{number | Promise}–以毫秒为单位的超时,或承诺 解决后应中止请求

    我成功地使用了它。它有点像这样

    export default function MyService($q, $http) {
      "ngInject";
      var service = {
        getStuff: getStuff,
      };
    
      let _cancelGetStuff = angular.noop;
    
      return service;
    
      function getStuff(args) {
        _cancelGetStuff(); // cancel any previous request that might be ongoing.
    
        let canceller = $q( resolve => { _cancelGetStuff = resolve; });
    
        return $http({
          method: "GET",
          url: <MYURL>
          params: args,
          timeout: canceller
        }).then(successCB, errorCB);
    
        function successCB (response) {
          return response.data;
        }
    
        function errorCB (error) {
          return $q.reject(error.data);
        }
      }
    }
    
    导出默认函数MyService($q,$http){
    "ngInject";;
    var服务={
    getStuff:getStuff,
    };
    让_cancelGetStuff=angular.noop;
    回程服务;
    函数getStuff(args){
    _cancelGetStuff();//取消以前可能正在进行的任何请求。
    让canceller=$q(resolve=>{u cancelGetStuff=resolve;});
    返回$http({
    方法:“获取”,
    网址:
    参数:args,
    超时:取消器
    }).然后(成功CB,错误CB);
    功能成功CB(响应){
    返回响应数据;
    }
    函数errorCB(错误){
    返回$q.reject(错误数据);
    }
    }
    }
    
    记住

  • 这假设您只需要上一个请求的结果
  • 被取消的请求仍会调用
    successCB
    ,但
    响应
    未定义的
  • 它也可以调用errorCB,
    error.status
    将是
    -1
    ,就像请求超时一样

  • $location.path('url').replace()将替换当前路由,而不是将其添加到堆栈中。我不确定您是否可以取消angular中的路由-您是否查看了ngRoute的源代码以找到答案?是的,确实如此!我将发布一个带有一些代码的答案,以供将来参考(以及其他人参考)。有趣的方法!如果这解决了您的问题,请接受您自己的答案。我明天才能接受:)我使用了类似的方法,但承诺链上不会定义.abort(),即allSitesPromise.then()。abort未定义。你有什么诀窍使.abort也沿着承诺链传播吗?我不懂r