$http
の timeout プロパティを使用してこれを行うことができ、request
とコールバックの両方を使用して、各リクエストをそれぞれresponseError
保存および実行します。$http
手順:
$http
コールバック プロセス内でサービスを遅延注入します。ファクトリの関数にサービスを注入すると循環依存が発生するためrequest
、これがサービスを取得する唯一の方法になります。$http
コールバックで渡された構成が処理されたかどうかを判断しrequest
ます。処理されていない場合は、構成をリクエスト スタックに追加し、優先度順に並べ替えます。$http
現在のリクエストをキャンセルするには、構成オブジェクトの timeout プロパティに解決された promise を追加します。最後に構成オブジェクトを返します。
$http
リクエストがキャンセルされたら、responseError
コールバックでキャッチします。リクエスト スタックにアイテムがある場合は、最初のアイテム (config) をポップし、遅延読み込み$http
サービスを使用して呼び出します。最後に、コールバックによって提供される reject パラメータを使用して、拒否された promise を返します。
デモ
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);
});
各リクエストが正しい順序で呼び出されたことを確認するには、コンソール タブでログを確認するか、ネットワーク タブでリクエストを確認します。
アップデート:
リクエストを順番に呼び出したい場合(次のリクエストが呼び出される前に最初のリクエストが終了する必要がある場合)、responseError
コールバックで私のソリューションを次のように微調整できます。
デモ
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
コメントで述べたように、優先順位付けされたリクエストによって返される約束は、期待される約束の解決または拒否を返しません。このようなシナリオに対応するために、次の方法でインターセプターを更新しました。
- 各 http 構成に関連する延期された promise を保存します。
responseError
リクエストの解決または拒否を維持するために、インターセプターで延期された promise を返します。
- 最後に、優先順位付けされたリクエストの繰り返しで延期された promise を使用します。
デモ
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);
});