如何取消$资源请求 [英] How to cancel $resource requests

查看:185
本文介绍了如何取消$资源请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找出如何使用$资源的超时属性来动态地取消挂起的请求。理想情况下,我想只是可以取消某些属性(根据发送的PARAMS)请求,但似乎这是不可能的。在此期间,我只是想取消所有挂起的请求,然后重新设置超时时间的承诺,允许新的请求。

I'm trying to figure out how to use the timeout property of a $resource to dynamically cancel pending requests. Ideally, I'd like to just be able to cancel requests with certain attributes (based on the params sent), but it seems this may not be possible. In the meantime, I'm just trying to cancel all pending requests, and then resetting the timeout promise to allow new requests.

这个问题似乎是在$资源配置只允许超时值单一,静态的承诺。这是有道理的,我怎么能做到这一点,如果我是做个体$ HTTP调用,因为我可以只通过在超时新的承诺,但如何能这项工作为$资源?我已经在这里建立了一个例子plunker:<一href=\"http://plnkr.co/edit/PP2tqDYXh1NAOU3yqCwP?p=$p$pview\">http://plnkr.co/edit/PP2tqDYXh1NAOU3yqCwP?p=$p$pview

The issue seems to be that the $resource configuration only allows a single, static promise for the timeout value. It makes sense how I could do this if I was making individual $http calls, since I could just pass in new promises for the timeout, but how can this work for a $resource? I have set up an example plunker here: http://plnkr.co/edit/PP2tqDYXh1NAOU3yqCwP?p=preview

下面是我的控制器code:

Here's my controller code:

app.controller('MainCtrl', function($scope, $timeout, $q, $resource) {
  $scope.canceller = $q.defer();
  $scope.pending = 0;
  $scope.actions = [];
  var API = $resource(
    'index.html', {}, {
      get: {
        method: 'GET',
        timeout: $scope.canceller.promise
      }
    }
  )

  $scope.fetchData = function() {
    if ($scope.pending) {
      $scope.abortPending();
    }
    $scope.pending = 1;
    $scope.actions.push('request');
    API.get({}, function() {
      $scope.actions.push('completed');
      $scope.pending = 0;
    }, function() {
      $scope.actions.push('aborted');
    });
  }

  $scope.abortPending = function() {
    $scope.canceller.resolve();
    $scope.canceller = $q.defer();
  }
});

现在,当有一个未决的请求消除工作,但我似乎并没有能够重新设置 - 一旦一个请求被中止,今后所有申请也将被中止

Right now, the canceller works when there is a pending request, but I don't seem to be able to reset it - once one request is aborted, all future requests will be aborted as well.

我敢肯定,我失去了一些东西,因为能够取消未决的请求似乎大多数Web应用程序的pretty关键功能(至少我建立的)。

I'm sure I'm missing something, since being able to cancel pending requests seems like a pretty crucial feature of most web applications (at least that I've built).

感谢

推荐答案

stefchri 回答对我的作品,但我不得不作出一些修改,以便:

Answer by stefchri works for me, but I had to make some modifications in order to:


  • 启用资源Ajax调用,而不需要被取消多次重建资源

  • 请资源向后兼容 - 这意味着没有必要改变任何应用程序(控制器)code除了资源工厂

  • 请code JSLint的标准

这是完整的服务工厂实现(你只需要把正确的模块名称):

This is complete service factory implementation (you just need to put proper module name):

'use strict';

/**
 * ResourceFactory creates cancelable resources.
 * Work based on: http://stackoverflow.com/a/25448672/1677187
 * which is based on: https://developer.rackspace.com/blog/cancelling-ajax-requests-in-angularjs-applications/
 */
/* global array */
angular.module('module_name').factory('ResourceFactory', ['$q', '$resource',
    function($q, $resource) {

        function abortablePromiseWrap(promise, deferred, outstanding) {
            promise.then(function() {
                deferred.resolve.apply(deferred, arguments);
            });

            promise.catch(function() {
                deferred.reject.apply(deferred, arguments);
            });

            /**
             * Remove from the outstanding array
             * on abort when deferred is rejected
             * and/or promise is resolved/rejected.
             */
            deferred.promise.finally(function() {
                array.remove(outstanding, deferred);
            });
            outstanding.push(deferred);
        }

        function createResource(url, options, actions) {
            var resource;
            var outstanding = [];
            actions = actions || {};

            Object.keys(actions).forEach(function(action) {
                var canceller = $q.defer();
                actions[action].timeout = canceller.promise;
                actions[action].Canceller = canceller;
            });

            resource = $resource(url, options, actions);

            Object.keys(actions).forEach(function(action) {
                var method = resource[action];

                resource[action] = function() {
                    var deferred = $q.defer(),
                    promise = method.apply(null, arguments).$promise;

                    abortablePromiseWrap(promise, deferred, outstanding);

                    return {
                        $promise: deferred.promise,

                        abort: function() {
                            deferred.reject('Aborted');
                        },
                        cancel: function() {
                            actions[action].Canceller.resolve('Call cancelled');

                            // Recreate canceler so that request can be executed again
                            var canceller = $q.defer();
                            actions[action].timeout = canceller.promise;
                            actions[action].Canceller = canceller;
                        }
                    };
                };
            });

            /**
             * Abort all the outstanding requests on
             * this $resource. Calls promise.reject() on outstanding [].
             */
            resource.abortAll = function() {
                for (var i = 0; i < outstanding.length; i++) {
                    outstanding[i].reject('Aborted all');
                }
                outstanding = [];
            };

            return resource;
        }

        return {
            createResource: function (url, options, actions) {
                return createResource(url, options, actions);
            }
        };
    }
]);

用法一样stefchri例子。服务工厂:

Usage is the same as in stefchri example. Service factory:

'use strict';

angular.module('module_name').factory('YourResourceServiceName', ['ResourceFactory', function(ResourceFactory) {
    return ResourceFactory.createResource('some/api/path/:id', { id: '@id' }, {
        create: {
            method: 'POST'
        },
        update: {
            method: 'PUT'
        }
    });
}]);

在控制器使用(向后兼容):

Usage in controller (backward compatible):

var result = YourResourceServiceName.create(data);
result.$promise.then(function success(data, responseHeaders) {
    // Successfully obtained data
}, function error(httpResponse) {
    if (httpResponse.status === 0 && httpResponse.data === null) { 
        // Request has been canceled
    } else { 
        // Server error 
    }
});
result.cancel(); // Cancels XHR request

替代做法:

var result = YourResourceServiceName.create(data);
result.$promise.then(function success(data, responseHeaders) {       
    // Successfully obtained data
}).catch(function (httpResponse) {
    if (httpResponse.status === 0 && httpResponse.data === null) { 
        // Request has been canceled
    } else { 
        // Server error 
    }
});
result.cancel(); // Cancels XHR request

进一步的改进:


  • 如果请求已被取消,我不喜欢检查。更好的方法是附加属性 HTT presponse.isCanceled 时请求被取消,以及类似的中止。

  • I don't like checking if request has been canceled. Better approach would be to attach attribute httpResponse.isCanceled when request is canceled, and similar for aborting.

这篇关于如何取消$资源请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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