3

大量の遅延データ読み込みを伴うアプリケーションに取り組んでいます。「priority」パラメータに基づいて http リクエストに優先順位を付けたいと思います。

これが使用のコンセプトです。

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

$http インターセプターの使用を考えていました。そんな感じ:

 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;

        }   
    };
});

しかし、ここで約束を返すことはできません。何か案は?

4

3 に答える 3

4

$httpの timeout プロパティを使用してこれを行うことができ、requestとコールバックの両方を使用して、各リクエストをそれぞれresponseError保存および実行します。$http

手順:

  1. $httpコールバック プロセス内でサービスを遅延注入します。ファクトリの関数にサービスを注入すると循環依存が発生するためrequest、これがサービスを取得する唯一の方法になります。$http

  2. コールバックで渡された構成が処理されたかどうかを判断しrequestます。処理されていない場合は、構成をリクエスト スタックに追加し、優先度順に並べ替えます。$http現在のリクエストをキャンセルするには、構成オブジェクトの timeout プロパティに解決された promise を追加します。最後に構成オブジェクトを返します。

  3. $httpリクエストがキャンセルされたら、responseErrorコールバックでキャッチします。リクエスト スタックにアイテムがある場合は、最初のアイテム (config) をポップし、遅延読み込み$httpサービスを使用して呼び出します。最後に、コールバックによって提供される reject パラメータを使用して、拒否された promise を返します。

デモ

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

  });

各リクエストが正しい順序で呼び出されたことを確認するには、コンソール タブでログを確認するか、ネットワーク タブでリクエストを確認します。

アップデート:

リクエストを順番に呼び出したい場合(次のリクエストが呼び出される前に最初のリクエストが終了する必要がある場合)、responseErrorコールバックで私のソリューションを次のように微調整できます。

デモ

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

コメントで述べたように、優先順位付けされたリクエストによって返される約束は、期待される約束の解決または拒否を返しません。このようなシナリオに対応するために、次の方法でインターセプターを更新しました。

  1. 各 http 構成に関連する延期された promise を保存します。
  2. responseErrorリクエストの解決または拒否を維持するために、インターセプターで延期された promise を返します。
  3. 最後に、優先順位付けされたリクエストの繰り返しで延期された promise を使用します。

デモ

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

  });
于 2015-02-11T12:30:44.447 に答える