添加排队到angulars $ http服务

Pat*_*ick 16 angularjs

我有一个非常古怪的api,一次只能处理一个请求.因此,我需要确保每次发出请求时,它都会进入队列,并且该队列一次执行一个请求,直到它为空.

通常,我只使用jQuery的内置队列,因为该站点已经在使用jQuery.但是,我不确定我是否能够以某种方式装饰$ http服务,或者将其包装在另一个一次返回一个promise的服务中,或者别的什么.

Val*_*nov 40

以下是我的解决方案:http://plnkr.co/edit/Tmjw0MCfSbBSgWRhFvcg

这个想法是:每次运行服务都会向队列添加请求并返回promise.当对$ 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;
  };
});
Run Code Online (Sandbox Code Playgroud)

看起来很简单:)


Ric*_*ard 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 );
            },
        };
    } ] );
} ] );

} )();
Run Code Online (Sandbox Code Playgroud)


pie*_*nik 5

理查德:你的代码很完美,但它也适用于内部请求,如template$templateProviders.

这是仅适用于外部http请求的解决方案

/**
 * Interceptor to queue HTTP requests.
 */
$httpProvider.interceptors.push(['$q', function ($q) {
    var _queue = [];

    /**
     * Executes the top function on the queue (if any).
     */
    function _executeTop() {
        if (_queue.length === 0) {
            return;
        }
        _queue[0]();
    }

    return {
        /**
         * Blocks each request on the queue. If the first request, processes immediately.
         */
        request: function (config) {
            if (config.url.substring(0, 4) == 'http') {
                var deferred = $q.defer();
                _queue.push(function () {
                    deferred.resolve(config);
                });
                if (_queue.length === 1) {
                    _executeTop();
                }
                return deferred.promise;
            } else {
                return config;
            }
        },
        /**
         * After each response completes, unblocks the next request.
         */
        response: function (response) {
            if (response.config.url.substring(0, 4) == 'http') {
                _queue.shift();
                _executeTop();
            }
            return response;
        },
        /**
         * After each response errors, unblocks the next request.
         */
        responseError: function (responseError) {
            if (responseError.config.url.substring(0, 4) == 'http') {
                _queue.shift();
                _executeTop();
            }
            return $q.reject(responseError);
        },
    };
}]);
Run Code Online (Sandbox Code Playgroud)