我正在试图弄清楚如何使用$ resource的timeout属性动态取消挂起的请求。理想情况下,我希望能够取消具有某些属性的请求(基于发送的参数),但似乎这可能是不可能的。与此同时,我只是尝试取消所有挂起的请求,然后重置超时承诺以允许新请求。
问题似乎是$ resource配置只允许一个静态的超时值承诺。如果我正在进行单独的$ http调用,那么我可以做到这一点是有道理的,因为我可以为超时传递新的承诺,但是如何才能为$资源工作呢?我在这里设置了一个示例plunker:http://plnkr.co/edit/PP2tqDYXh1NAOU3yqCwP?p=preview
这是我的控制器代码:
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();
}
});
现在,当有待处理的请求时,取消器工作,但我似乎无法重置它 - 一旦一个请求被中止,所有未来的请求也将被中止。
我确定我错过了一些东西,因为能够取消待处理的请求似乎是大多数Web应用程序的一个非常重要的功能(至少我已经构建了)。
由于
答案 0 :(得分:10)
Gecko IT的回答对我有用,但我必须做一些修改才能:
这是完整的服务工厂实现(您只需要输入正确的模块名称):
'use strict';
/**
* ResourceFactory creates cancelable resources.
* Work based on: https://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);
}
};
}
]);
用法与Gecko IT示例相同。服务工厂:
'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'
}
});
}]);
控制器中的用法(向后兼容):
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
进一步改进:
httpResponse.isCanceled
,并且类似于中止。 答案 1 :(得分:2)
(对于Angular 1.2.28+)大家好,我只是想让它易于理解,我如何处理该问题如下:
这里我声明了超时参数
$scope.stopRequestGetAllQuestions=$q.defer();
然后在我使用它如下
return $resource(urlToGet, {}, {get:{ timeout: stopRequestGetAllQuestions.promise }});
如果我想停止以前的$ resource调用,我只需要解析这个stopRequestGetAllQuestions对象。
stopRequestGetAllQuestions.resolve();
但如果我想停止之前的那个并开始一个新的$ resource调用,那么我会在stopRequestGetAllQuestions.resolve();
之后执行此操作:
stopRequestGetAllQuestions = $q.defer();
答案 2 :(得分:1)
目前有很多例子。 我发现以下两个内容非常丰富:
这一个显示了如何处理$ resource和$ http请求的示例: https://developer.rackspace.com/blog/cancelling-ajax-requests-in-angularjs-applications/
和
这个更简单,只适用于$ http: http://odetocode.com/blogs/scott/archive/2014/04/24/canceling-http-requests-in-angularjs.aspx
答案 3 :(得分:1)
您好我根据https://developer.rackspace.com/blog/...
制作了自定义处理程序.factory('ResourceFactory', ["$q", "$resource", function($q, $resource) {
function createResource(url, options, actions) {
var actions = actions || {},
resource,
outstanding = [];
Object.keys(actions).forEach(function (action) {
console.log(actions[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 () {
console.log(actions[action]);
actions[action].Canceller.resolve("Call cancelled");
}
};
};
});
/**
* 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);
}
}
}])
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);
}
//Usage SERVICE
factory("ServiceFactory", ["apiBasePath", "$resource", "ResourceFactory", function (apiBasePath, $resource, QiteResourceFactory) {
return ResourceFactory.createResource(apiBasePath + "service/:id", { id: '@id' }, null);
}])
//Usage Controller
var result = ServiceFactory.get();
console.log(result);
result.promise.then(function (data) {
$scope.services = data;
}).catch(function (a) {
console.log("catch", a);
})
//Actually cancels xhr request
result.cancel();
答案 4 :(得分:0)
一种解决方案是每次需要时重新创建资源。
// for canceling an ajax request
$scope.canceler = $q.defer();
// create a resource
// (we have to re-craete it every time because this is the only
// way to renew the promise)
function getAPI(promise) {
return $resource(
'index.html', {}, {
get: {
method: 'GET',
timeout: promise
}
}
);
}
$scope.fetchData = function() {
// abort previous requests if they are still running
$scope.canceler.resolve();
// create a new canceler
$scope.canceler = $q.defer();
// instead of using "API.get" we use "getAPI().get"
getAPI( $scope.canceler.promise ).get({}, function() {
$scope.actions.push('completed');
$scope.pending = 0;
}, function() {
$scope.actions.push('aborted');
});
}
答案 5 :(得分:0)
在我们尝试解决此任务时,我们得到了以下解决方案:
<!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>
有关详细信息,请查看“Cancel Angularjs resource request”。