一度に 1 つのリクエストしか処理できない非常に風変わりな API があります。したがって、リクエストが行われるたびにキューに入れられ、キューが空になるまで一度に 1 つのリクエストが実行されるようにする必要があります。
サイトはすでに jQuery を使用しているため、通常は jQuery の組み込みキューを使用します。しかし、どうにかして $http サービスをデコレートできるかどうか、一度に 1 つの promise を返す別のサービスにラップできるかどうかはわかりませんでした。
一度に 1 つのリクエストしか処理できない非常に風変わりな API があります。したがって、リクエストが行われるたびにキューに入れられ、キューが空になるまで一度に 1 つのリクエストが実行されるようにする必要があります。
サイトはすでに jQuery を使用しているため、通常は jQuery の組み込みキューを使用します。しかし、どうにかして $http サービスをデコレートできるかどうか、一度に 1 つの promise を返す別のサービスにラップできるかどうかはわかりませんでした。
これが私の解決策です:http://plnkr.co/edit/Tmjw0MCfSbBSgWRhFvcg
アイデアは次のとおりです。サービスの実行ごとにリクエストがキューに追加され、プロミスが返されます。$http へのリクエストが終了したら、返された promise を解決/拒否し、次のタスクがあればキューから実行します。
app.factory('srv', function($q,$http) {
var queue=[];
var execNext = function() {
var task = queue[0];
$http(task.c).then(function(data) {
queue.shift();
task.d.resolve(data);
if (queue.length>0) execNext();
}, function(err) {
queue.shift();
task.d.reject(err);
if (queue.length>0) execNext();
})
;
};
return function(config) {
var d = $q.defer();
queue.push({c:config,d:d});
if (queue.length===1) execNext();
return d.promise;
};
});
とてもシンプルに見えます:)
上記の Valentyn の優れた作業に基づいて、このコードをスタンドアロンの Angular (v1.2+) リクエスト/レスポンス インターセプターにまとめました。どこでも$http
使用するためにコードを作り直す必要なく、リクエストを自動的にキューに入れます。srv()
( function() {
'use strict';
angular.module( 'app' ).config( [ '$httpProvider', function( $httpProvider ) {
/**
* Interceptor to queue HTTP requests.
*/
$httpProvider.interceptors.push( [ '$q', function( $q ) {
var _queue = [];
/**
* Shifts and executes the top function on the queue (if any). Note this function executes asynchronously (with a timeout of 1). This
* gives 'response' and 'responseError' chance to return their values and have them processed by their calling 'success' or 'error'
* methods. This is important if 'success' involves updating some timestamp on some object which the next message in the queue relies
* upon.
*/
function _shiftAndExecuteTop() {
setTimeout( function() {
_queue.shift();
if ( _queue.length > 0 ) {
_queue[0]();
}
}, 1 );
}
return {
/**
* Blocks each request on the queue. If the first request, processes immediately.
*/
request: function( config ) {
var deferred = $q.defer();
_queue.push( function() {
deferred.resolve( config );
} );
if ( _queue.length === 1 ) {
_queue[0]();
}
return deferred.promise;
},
/**
* After each response completes, unblocks the next request.
*/
response: function( response ) {
_shiftAndExecuteTop();
return response;
},
/**
* After each response errors, unblocks the next request.
*/
responseError: function( responseError ) {
_shiftAndExecuteTop();
return $q.reject( responseError );
},
};
} ] );
} ] );
} )();