2015-02-11 7 views
3

Я работаю над приложением с большим количеством ленивых данных. Я хотел бы определить приоритеты http-запросов на основе параметра «priority».

Это концепция его использования.

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

     } 
    }; 
}); 

Но я не могу вернуть обещание здесь. Есть идеи?

ответ

5

Вы можете сделать это путем использования тайм-аута собственности $http «s, и использовать оба request и responseError обратных вызовов, чтобы сохранить и выполнить каждый $http запросы соответственно.

Шаги:

  1. Лениво впрыскивать $http услуги в процессе request обратного вызова, это будет единственным способом получить $http обслуживания, потому что впрыскивание в функции завода вызывает циклическую зависимость.

  2. Определить, была ли обработана конфигурация, прошедшая в обратном вызове request. Если он не был обработан, добавьте конфигурацию в стек запроса и отсортируйте его по приоритету. Добавьте разрешенное обещание в свойство тайм-аута объекта конфигурации, чтобы отменить текущий запрос $http. Наконец верните объект конфигурации.

  3. После того, как запрос $http был отменен, поймайте его в обратном вызове responseError. Если в стеке запросов есть элементы, поместите первый элемент (config) и вызовите его с помощью ленивого загруженного сервиса $http. Наконец, возвратите отклоненное обещание, используя параметр отклонения, предоставляемый обратным вызовом.

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

    }); 

Чтобы убедиться, что каждый запрос был вызван в правильном порядке, вы можете проверить журналы на вкладке консоли или запросов на вкладке сети.

Update:

Если вы хотите, чтобы ваши запросы вызываются в порядке (когда первый запрос должен завершиться до следующего запроса вызывает), то вы можете настроить свое решение в responseError обратного вызова, чтобы что-то вроде этого:

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

Это тип решения, которое я искал. Я постараюсь его реализовать. Благодаря! – krystiangw

+0

ryeballar Мне понравился ваш ответ, но обещания, которые вы поместили в стек запроса после копирования, похоже, не выполняют ранее обещанный код. На самом деле более элегантным решением было бы отложить выполнение в том месте, где вы размещаете свой запрос в стеке, но я не могу найти хороший способ сделать это. –

+0

Можете ли вы предоставить эквивалент plnkr или или jsfiddle для такого случая? – ryeballar

1

Попробуйте обернуть ваш тайм-аут

var deferred = $q.defer(); 
     (function (_deferred){ 
     var intervalPromise = $interval(function(){ 

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

     }, 100); 
     })(deferred); 
return deferred.promise; 

Похоже, он заблудился на $ интервале. а также ваш отложенный был установленный глобальный набор var раньше.

+0

Да, вы правы. Но, поскольку я упоминал проблему, я не могу здесь пообещать. Он принимает только объект 'config'. – krystiangw

+0

Копайте немного немного в методе $ http.get, не видите возможности установить свой приоритет в этом. Может быть, создать собственный сервис для обработки этого и приоритета, прежде чем вы вызовете $ http.get? 'service.httpGet (url, {priority: 1});'? – graphefruit

0

Это не было правильным решением. Вы можете добиться этого, написав свой собственный сервис, чтобы назначить приоритет вашей очереди вызовов api перед вызовом http get.

Это не будет работать для следующего случая использования Angular Http Priority