Add queueing to angulars $http service

angular 6 queue
angular queue
angular queue http requests
rxjs queue http requests
angular httpclient priority

I have a very quirky api that can only handle a single request at a time. Therefore, I need to ensure that every time a request is made, it goes into a queue, and that queue is executed one request at a time, until it is empty.

Normally, I just use jQuery's built in queue, since the site is already using jQuery. However, I was not sure if I could somehow decorate the $http service, or wrap it in another service that returns one promise at a time, or something else.

Here is my solution for that: http://plnkr.co/edit/Tmjw0MCfSbBSgWRhFvcg

The idea is: each run of service add request to queue and return promise. When request to $http is finished resolve/refuse returned promise and execute next task from queue if any.

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;
  };
});

Looks quite simple :)

Add queueing to Angular's HttpClient, I have exact same requirement as mentioned in Add queueing to angulars $http service but need implementation in Angular 4.3 or 5 using the HttpInterceptor� You can do this relatively easily. A naive example follows bellow. It lacks typing etc, it's not elaborate, it has a few weak points, and it would be better to extract the queueing part and http-requesting part into different services or classes, but this should get you started.

Richard: Your code works perfect but it also works with inner request like template or $templateProviders.

Here is solution to work only with external http requests

/**
 * 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);
        },
    };
}]);

How to prioritize certain HTTP requests from a Queue: Angular (2+) , Add Mock Service with fake HTTP Calls. As displayed above, the second HTTP request will be the request that should be fired first, but for� The messages will look better when you add the private CSS styles to messages.component.css as listed in one of the "final code review" tabs below. Add additional messages to hero servicelink. The following example shows how to send and display a message each time the user clicks on a hero, showing a history of the user's selections.

Building on Valentyn's great work above, I rolled this code into a standalone Angular (v1.2+) request/response interceptor. It will queue $http requests automatically without needing to rework your code to use srv() everywhere:

( 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 );
            },
        };
    } ] );
} ] );

} )();

Add queueing to Angular's HttpClient - angular - html, I have exact same requirement as mentioned in Add queueing to angulars $http service but need implementation in Angular 4.3 or 5 using the HttpInterceptor� Param Type Details; config object: Object describing the request to be made and how it should be processed. The object has following properties:

.factory('qHttp', function($q, $http) {
  var queue = $q.when();

  return function queuedHttp(httpConf) {
    var f = function(data) {
      return $http(httpConf);
    };
    return queue = queue.then(f, f);
  };
})

How to use:

var apis = ['//httpbin.org/ip', '//httpbin.org/user-agent', '//httpbin.org/headers'];

for (var i = 0; i < 100; i++) {
  qHttp({
    method: 'get', 
    url: apis[i % apis.length]
  })
  .then(function(data) { 
    console.log(data.data); 
  });
}

Queue ajax requests or any function in AngularJS, For such cases we've got a queuing service for your AngularJS app. Let's say that XHR finished loading: GET "http://localhost:8000/results.json?". Now the refresh function just adds real "doRefresh" function to queue. Http Service will help us fetch external data, post to it, etc. We need to import the http module to make use of the http service. Let us consider an example to understand how to make use of the http service. To start using the http service, we need to import the module in app.module.ts as shown

If someone need solution to sequential http calls (as mentioned by OP) in Angular 5 then following is the solution:

    import { Injectable } from '@angular/core';
    import { Response } from '@angular/http';
    import { HttpClient } from '@angular/common/http';
    import { Observable } from 'rxjs/Observable';
    import { Subject } from 'rxjs/Subject'

    export class PendingRequest {
      url: string;
      method: string;
      options: any;
      subscription: Subject<any>;

      constructor(url: string, method: string, options: any, subscription: Subject<any>) {
        this.url = url;
        this.method = method;
        this.options = options;
        this.subscription = subscription;
      }
    }

    @Injectable()
    export class BackendService {
      private requests$ = new Subject<any>();
      private queue: PendingRequest[] = [];

      constructor(private httpClient: HttpClient) {
        this.requests$.subscribe(request => this.execute(request));
      }

      /** Call this method to add your http request to queue */
      invoke(url, method, params, options) {
        return this.addRequestToQueue(url, method, params, options);
      }

      private execute(requestData) {
        //One can enhance below method to fire post/put as well. (somehow .finally is not working for me)
        const req = this.httpClient.get(requestData.url)
          .subscribe(res => {
            const sub = requestData.subscription;
            sub.next(res);
            this.queue.shift();
            this.startNextRequest();
          });
      }

      private addRequestToQueue(url, method, params, options) {
        const sub = new Subject<any>();
        const request = new PendingRequest(url, method, options, sub);

        this.queue.push(request);
        if (this.queue.length === 1) {
          this.startNextRequest();
        }
        return sub;
      }

      private startNextRequest() {
        // get next request, if any.
        if (this.queue.length > 0) {
          this.execute(this.queue[0]);
        }
      }
    }

In case of someone wants to look at working plunker then here is the working plunker.

Multiple HTTP Requests in Angular, Quick guide on how to do multiple HTTP requests in Angular - either sequentially or in parallel. angular.js getting location with html5 location api and reverse geocoding - agularjs reverse geocoding

Communicating with backend services using HTTP, In Adding headers, for example, the service set the default headers using the headers option property. Use the params property to configure a request with HTTP� We use cookies to personalize content and ads, to provide the best browsing experience possible, to provide social media features and to analyse our traffic.

Add queueing to angulars $http service – Angular Questions, Add queueing to angulars $http service. Posted on July 21, 2018 by lzo. I have a very quirky api that can only handle a single request at a time. Therefore, I need� Testing is important. That’s why Angular comes with a testing story out-of-the-box. Due to its dependency injection system, it’s fairly easy to mock dependencies, swap out Angular modules, or even create so called “shallow” tests, which enable us to test Angular components, without actually depending on their views (DOM).

serhiisol/ngx-request-queue: Angular 4.3.0+ Request , Contribute to serhiisol/ngx-request-queue development by creating an npm install ngx-request-queue --save npm install @decorators/common --save Import QueueService interface to implement it with your custom queue service, e.g.: from '@angular/core'; import { HttpClientModule } from '@angular/common /http';�

Comments
  • How are you planning on using the queue? Are the callers all the same? Or do you want to have one promise returned per caller, but executed by $http in series?
  • >>Or do you want to have one promise returned per caller, but executed by $http in series? - this is what I am looking for. Essentially if I could get an interceptor able to delay the http request until all other requests before it have succeeded, that would be great.
  • This seems super promising, but I don't understand how you handle success/error responses using this. Thanks for your help!
  • Rereading my comment made it seem less clear than I thought it was originally. When I call srv() in the controller, how do I set up a success and an error response (you use .then, which seems to mean there is only one possible reaction to the response). Thanks again
  • @Patrick when you call srv, it returns a promise that has success, error, and then methods. See $q.
  • In case of successfull response I just resolve returned promise. In case of error I reject. So depending on response you will get called first callback or second callback of then function. Actually another solution is to chain promises, but it is not so ovious solution...
  • I used this post while writing service to wrap Google's Geocoding API (which limits the frequency of requests). I came up with something that 1) queries the server serially, 2) caches the results in localStorage, and 3) responds appropriately to the error codes from the API. Hope it's useful to someone : gist.github.com/benmj/6380466
  • Thanks for the enhancement! I'm not sure why you need to re-check config.url in response/responseError though? If the call is non-http, I understand it won't block, but is there harm in shifting the queue anyway?
  • You have to use it because response is always executed
  • You have to use it because response and responseError are always executed - even without promise. That's why You have to check http
  • If you're using relative URL like /api/... then the check for config.url.substring will always fail. I've replaced with different property that I also use to queue specific type of calls, and not all. if (config.queue) { and then in the request e.g. $http.get(url, {queue:true}).. So you can choose which type of requests you want to queue.
  • can you add a bit more context to explain how someone might use this in their app?
  • Best and easy answer.