本文介绍了如何在有角度的$ http服务中确定请求的优先级?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理具有大量惰性数据加载的应用程序.我想根据优先级"参数对HTTP请求进行优先级排序.

I'm working on an application with a large amount of lazy data loading. I would like to prioritize http requests based on 'priority' param.

这是使用它的概念.

$http.get(url, {params: query, priority: 1})

我当时正在考虑使用$ http拦截器.像这样的东西:

I was thinking of using $http interceptors. Something like that:

 angular.module('myModule')
.factory('httpPriorityInterceptor', function ($interval, $q) {
    var requestStack = [];

    return {
        request: function (config) {

            config.priority = config.priority || 3;

            requestStack.push(config);
            requestStack.sort(sortByPriority);

            if (isFirstToGo(item)) return requestStack.pop();

            deferred = $q.defer();

            var intervalPromise = $interval(function(){

                if (isFirstToGo(item)) {
                    deferred.resolve(requestStack.pop());
                    $interval.cancel(intervalPromise);
                };

            }, 100);

            return deferred.promise;

        }
    };
});

但是我不能在这里退还诺言.有任何想法吗?

But I can't return promise here. Any ideas?

推荐答案

您可以使用$http的timeout属性,并使用requestresponseError回调保存并执行每个$http分别请求.

You can do this by making use of $http's timeout property, and use both request and responseError callbacks to save and execute each $http requests respectively.

步骤:

  1. request回调过程中延迟注入$http服务,这将是获取$http服务的唯一方法,因为将其注入工厂函数会导致循环依赖.

  1. Lazily inject the $http service within the request callback process, this will be the only way to get the $http service because injecting it in the factory's function causes circular dependency.

确定是否已处理在request回调中传递的配置.如果尚未处理,则将配置添加到请求堆栈中,并按优先级对其进行排序.在配置对象的timeout属性中添加一个已解决的Promise,以取消当前的$http请求.最后返回配置对象.

Determine if the configuration passed in the request callback has been processed. If it has not been processed then add the configuration in the request stack and sort it by priority. Add a resolved promise in the timeout property of the configuration object, to cancel the current $http request. Finally return the configuration object.

一旦取消了$http请求,请在responseError回调中捕获该请求.如果请求堆栈中有项目,请弹出第一个项目(配置),然后使用延迟加载的$http服务调用它.最后,使用回调提供的拒绝参数返回被拒绝的承诺.

Once the $http request has been cancelled, catch it in the responseError callback. If there are items in the request stack, pop the first item(config) and invoke it using the lazy loaded $http service. Lastly return a rejected promise using the rejection parameter provided by the callback.

演示

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

  });

要确保已按正确的顺序调用每个请求,可以检查控制台选项卡中的日志或网络选项卡中的请求.

To make sure that each request has been invoked in the right order, you can check the logs in the console tab or the requests in the network tab.

更新:

如果要按顺序调用请求(当第一个请求必须在下一个请求调用之前完成时),则可以在responseError回调中将我的解决方案调整为以下内容:

If you want your requests invoked in order (when the first request must finish before the next request invokes) then you can tweak my solution in the responseError callback to something like this:

演示

DEMO

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

如评论中所述,优先级请求返回的承诺不会返回预期的承诺解决方案或拒绝.我已经通过以下方式更新了拦截器以适应这种情况:

As mentioned in the comments, the promise returned by prioritized requests do not return the expected promise resolution or rejection. I have updated the interceptor to accommodate such scenario by:

  1. 相对于每个http配置保存延迟的承诺.
  2. responseError拦截器中返回延迟的诺言,以保持请求的解决或拒绝.
  3. 最后在优先请求的迭代中使用递延承诺.
  1. Saving a deferred promise relative to each http config.
  2. Return the deferred promise in the responseError interceptor for sake keeping the resolution or rejection of the request.
  3. Finally use the deferred promise in the iteration of prioritized requests.


演示


DEMO

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

  });

这篇关于如何在有角度的$ http服务中确定请求的优先级?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-22 18:07