16

一度に 1 つのリクエストしか処理できない非常に風変わりな API があります。したがって、リクエストが行われるたびにキューに入れられ、キューが空になるまで一度に 1 つのリクエストが実行されるようにする必要があります。

サイトはすでに jQuery を使用しているため、通常は jQuery の組み込みキューを使用します。しかし、どうにかして $http サービスをデコレートできるかどうか、一度に 1 つの promise を返す別のサービスにラップできるかどうかはわかりませんでした。

4

6 に答える 6

40

これが私の解決策です: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;
  };
});

とてもシンプルに見えます:)

于 2013-01-22T21:23:42.503 に答える
5

上記の 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 );
            },
        };
    } ] );
} ] );

} )();
于 2015-01-22T04:56:23.890 に答える