问题描述
我正在处理具有大量惰性数据加载的应用程序.我想根据优先级"参数对HTTP请求进行优先级排序.
I'm working on an application with a large amount of lazy data loading. I would like to prioritize http requests based on 'priority' param.
这是使用它的概念.
$http.get(url, {params: query, priority: 1})
我当时正在考虑使用$ http拦截器.像这样的东西:
I was thinking of using $http interceptors. Something like that:
angular.module('myModule')
.factory('httpPriorityInterceptor', function ($interval, $q) {
var requestStack = [];
return {
request: function (config) {
config.priority = config.priority || 3;
requestStack.push(config);
requestStack.sort(sortByPriority);
if (isFirstToGo(item)) return requestStack.pop();
deferred = $q.defer();
var intervalPromise = $interval(function(){
if (isFirstToGo(item)) {
deferred.resolve(requestStack.pop());
$interval.cancel(intervalPromise);
};
}, 100);
return deferred.promise;
}
};
});
但是我不能在这里退还诺言.有任何想法吗?
But I can't return promise here. Any ideas?
推荐答案
您可以使用$http
的timeout属性,并使用request
和responseError
回调保存并执行每个$http
分别请求.
You can do this by making use of $http
's timeout property, and use both request
and responseError
callbacks to save and execute each $http
requests respectively.
步骤:
-
在
request
回调过程中延迟注入$http
服务,这将是获取$http
服务的唯一方法,因为将其注入工厂函数会导致循环依赖.
Lazily inject the
$http
service within therequest
callback process, this will be the only way to get the$http
service because injecting it in the factory's function causes circular dependency.
确定是否已处理在request
回调中传递的配置.如果尚未处理,则将配置添加到请求堆栈中,并按优先级对其进行排序.在配置对象的timeout属性中添加一个已解决的Promise,以取消当前的$http
请求.最后返回配置对象.
Determine if the configuration passed in the request
callback has been processed. If it has not been processed then add the configuration in the request stack and sort it by priority. Add a resolved promise in the timeout property of the configuration object, to cancel the current $http
request. Finally return the configuration object.
一旦取消了$http
请求,请在responseError
回调中捕获该请求.如果请求堆栈中有项目,请弹出第一个项目(配置),然后使用延迟加载的$http
服务调用它.最后,使用回调提供的拒绝参数返回被拒绝的承诺.
Once the $http
request has been cancelled, catch it in the responseError
callback. If there are items in the request stack, pop the first item(config) and invoke it using the lazy loaded $http
service. Lastly return a rejected promise using the rejection parameter provided by the callback.
angular.module('demo', [])
.config(function($httpProvider) {
$httpProvider.interceptors.push('httpPriorityInterceptor');
})
.factory('httpPriorityInterceptor', function($q, $injector) {
var requestStack = [], // request stack
$http = null; // http service to be lazy loaded
return {
request: request, // request callback
responseError: responseError // responseError callback
};
// comparison function to sort request stack priority
function sort(config1, config2) {
return config1.priority < config2.priority;
}
function request(config) {
// Lazy load $http service
if(!$http) {
$http = $injector.get('$http');
}
// check if configuration has not been requested
if(!config.hasBeenRequested) {
// set indicator that configuration has been requested
config.hasBeenRequested = true;
// set default priority if not present
config.priority = config.priority || 3;
// add a copy of the configuration
// to prevent it from copying the timeout property
requestStack.push(angular.copy(config));
// sort each configuration by priority
requestStack = requestStack.sort(sort);
// cancel request by adding a resolved promise
config.timeout = $q.when();
}
// return config
return config;
}
function responseError(rejection) {
// check if there are requests to be processed
if(requestStack.length > 0) {
// pop the top most priority
var config = requestStack.pop();
console.log(config);
// process the configuration
$http(config);
}
// return rejected request
return $q.reject(rejection);
}
})
.run(function($http) {
// create http request
var createRequest = function(priority) {
$http.get('/priority/' + priority, {priority: priority});
};
createRequest(3);
createRequest(1);
createRequest(4);
createRequest(2);
});
要确保已按正确的顺序调用每个请求,可以检查控制台选项卡中的日志或网络选项卡中的请求.
To make sure that each request has been invoked in the right order, you can check the logs in the console tab or the requests in the network tab.
更新:
如果要按顺序调用请求(当第一个请求必须在下一个请求调用之前完成时),则可以在responseError
回调中将我的解决方案调整为以下内容:
If you want your requests invoked in order (when the first request must finish before the next request invokes) then you can tweak my solution in the responseError
callback to something like this:
DEMO
function responseError(rejection) {
// check if there are requests to be processed
if(requestStack.length > 0) {
requestStack.reduceRight(function(promise, config) {
return promise.finally(function() {
return $http(config);
});
}, $q.when());
requestStack.length = 0;
}
// return rejected request
return $q.reject(rejection);
}
更新06/16/2019
如评论中所述,优先级请求返回的承诺不会返回预期的承诺解决方案或拒绝.我已经通过以下方式更新了拦截器以适应这种情况:
As mentioned in the comments, the promise returned by prioritized requests do not return the expected promise resolution or rejection. I have updated the interceptor to accommodate such scenario by:
- 相对于每个http配置保存延迟的承诺.
- 在
responseError
拦截器中返回延迟的诺言,以保持请求的解决或拒绝. - 最后在优先请求的迭代中使用递延承诺.
- Saving a deferred promise relative to each http config.
- Return the deferred promise in the
responseError
interceptor for sake keeping the resolution or rejection of the request. - Finally use the deferred promise in the iteration of prioritized requests.
DEMO
angular.module('demo', [])
.config(function($httpProvider) {
$httpProvider.interceptors.push('httpPriorityInterceptor');
})
.factory('httpPriorityInterceptor', function($q, $injector) {
var requestStack = [], // request stack
$http = null; // http service to be lazy loaded
return {
request: request, // request callback
responseError: responseError // responseError callback
};
// comparison function to sort request stack priority
function sort(config1, config2) {
return config1.priority < config2.priority;
}
function request(config) {
// Lazy load $http service
if(!$http) {
$http = $injector.get('$http');
}
// check if configuration has not been requested
if(!config.hasBeenRequested) {
// set indicator that configuration has been requested
config.hasBeenRequested = true;
// set default priority if not present
config.priority = config.priority || 3;
// add a defered promise relative to the config requested
config.$$defer = $q.defer();
// add a copy of the configuration
// to prevent it from copying the timeout property
requestStack.push(angular.copy(config));
// sort each configuration by priority
requestStack = requestStack.sort(sort);
// cancel request by adding a resolved promise
config.timeout = $q.when();
}
// return config
return config;
}
function responseError(rejection) {
// check if there are requests to be processed
if(requestStack.length > 0) {
requestStack.reduceRight(function(promise, config) {
var defer = config.$$defer;
delete config.$$defer;
return promise.finally(function() {
return $http(config)
.then(function(response) {
defer.resolve(response);
})
.catch(function(error) {
defer.reject(error);
});
});
}, $q.when());
requestStack.length = 0;
}
return rejection.config.$$defer.promise;
}
})
.run(function($http) {
// create http request
var createRequest = function(priority) {
return $http.get(priority + '.json', {priority: priority});
};
createRequest(3);
createRequest(1).then(function(data) { console.log(data); })
createRequest(4);
createRequest(2);
});
这篇关于如何在有角度的$ http服务中确定请求的优先级?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!