5

Вопрос:Порядок обещаний в AngularJS

Есть ли «легкий» способ отменить ($q -/$http -) обещает в AngularJS или определить порядок, в котором обещает были решены?

Пример

У меня долго работает расчет и я запросить результат через $http. Некоторые действия или события требуют от меня перезапустить расчет (и, таким образом, отправить новый запрос $http) до того, как будет устранено первоначальное обещание. Таким образом, я полагаю, я не могу использовать простую реализацию как

$http.post().then(function(){ 
    //apply data to view 
}) 

, потому что я не могу гарантировать, что ответы возвращаются в том порядке, в котором я послал запросы - в конце концов я хочу показать результат последний расчет, когда все обещания были решены должным образом.

Однако я хотел бы избежать ожидания первого ответа, пока я не послать новый запрос, как это:

const timeExpensiveCalculation = function(){ 
    return $http.post().then(function(response){ 
     if (isNewCalculationChained) {return timeExpensiveCalculation();}    
     else {return response.data;} 
    }) 
} 

Мысли:

При использовании $http я могу получить доступ к конфи объект на ответ, чтобы использовать некоторые временные метки или другие идентификаторы, чтобы вручную заказывать входящие ответы. Однако я надеялся, что могу просто сказать угловатое как-то отменить устаревшее обещание и, таким образом, не запускать функцию .then(), когда он будет разрешен.

Это не работает без ручной реализации для $q -продается вместо $http.

Возможно, просто отказ от обещания - это путь? Но в обоих случаях это может продолжаться вечно до тех пор, пока, наконец, обещание не будет разрешено до того, как будет сформирован следующий запрос (что приводит к пустому виду в то же время).

Есть ли какая-то угловая API-функция, которую я пропущу, или есть прочные шаблоны дизайна или «трюки» с цепочкой обещаний или $ q.all для обработки нескольких обещаний, которые возвращают «одни и те же» данные?

+0

Не знаете, что вы используете для API, но в моем .Net apis. Я использовал SignalR для обработки таких сценариев. – jbrown

+1

Большой вопрос, с нетерпением жду ответов. Но разве было бы намного легче справиться с логикой внутри. Затем вместо того, чтобы пытаться избежать обещания от решения? – user2263572

+0

Возможный дубликат [Обещание - можно ли отменить обещание] (http://stackoverflow.com/questions/30233302/promise-is-it-possible-to-force-cancel-a-promise) –

ответ

3

Я делаю это путем создания requestId, и в then() функции Обещание, я проверить, если ответ приходит из самых последних requestId.

Хотя этот подход фактически не отменяет предыдущие обещания, он обеспечивает быстрый и простой способ гарантировать, что вы обрабатываете ответ последнего запроса.

Что-то вроде:

var activeRequest; 
function doRequest(params){ 
    // requestId is the id for the request being made in this function call 
    var requestId = angular.toJson(params); // I usually md5 hash this 

    // activeRequest will always be the last requestId sent out 
    activeRequest = requestId; 

    $http.get('/api/something', {data: params}) 
     .then(function(res){ 
      if(activeRequest == requestId){ 
       // this is the response for last request 

       // activeRequest is now handled, so clear it out 
       activeRequest = undefined; 
      } 
      else { 
       // response from previous request (typically gets ignored) 
      } 
     }); 
} 

Edit: На боковой ноте я хотел бы добавить, что эта концепция отслеживания requestId's также может применяться для предотвращения дублирования запросов. Например, в методе load(module, id) моего Data сервиса, я немного процесс, как это:

  1. генерировать requestId на основе URL + параметров.
  2. регистрация запросов хэш-таблицы для requestId

    • если requestId не найден: создать новый запрос и хранить обещание в хэш-таблице
    • если requestId найдено: просто вернуть обещание из хэша -таблица
  3. Когда запрос заканчивается, удалите запись requestId из хеш-таблицы.

+0

Спасибо большое! Я соглашусь с этим ответом, поскольку на самом деле это относится к angularJS, о чем я и просил.Ответ Redu содержит рабочий пример для этой техники (без использования Angular) –

4

Отмена обещания просто не вызывает функции onFulfilled и onRejected на этапе then. Так как @ user2263572 упомянул, что всегда лучше отказаться от обещания, которое не отменено (ES6 родные обещания не могут быть отменены в любом случае) и обрабатывать это условие на этапе then (например, игнорируя задачу, если для глобальной переменной установлено значение 2, как показано в следующий фрагмент), и я уверен, вы можете найти множество других способов сделать это. Одним из примеров может быть:

Извините, что я использую v (выглядит как обратный характер) для resolve и x (очевидный) для reject функций.

var prom1 = new Promise((v,x) => setTimeout(v.bind(null,"You shall not read this"),2000)), 
 
     prom2, 
 
validPromise = 1; 
 
prom1.then(val => validPromise === 1 && console.log(val)); 
 
// oh what have i done..!?! Now i have to fire a new promise 
 
prom2 = new Promise((v,x) => setTimeout(v.bind(null,"This is what you will see"),3000)); 
 
validPromise = 2; 
 
prom2.then(val => validPromise === 2 && console.log(val));

0

Я все еще пытаюсь выяснить, хороший способ для модульного тестирования этого, но вы можете попробовать этот вид стратегии:

var canceller = $q.defer(); 
service.sendCalculationRequest = function() { 
    canceller.resolve(); 
    return $http({ 
     method: 'GET', 
     url: '/do-calculation', 
     timeout: canceller.promise 
    }); 
}; 
+0

Я нашел это в другом потоке после того, как я разместил этот вопрос. Тем не менее, это работает только для вызовов $ http. –

+0

А я вижу, так что вы ищете что-то с '$ resource'. –

0

В ECMA6 обещаниям, there is a Promise.race(promiseArray) method. Это требует множества обещаний в качестве аргумента и возвращает одно обещание. Первое обещание разрешить в массиве передаст его разрешенное значение .then возвращенного обещания, в то время как другие обещания массива, которые появились во втором и т. Д., Не будут ожидаться.

Пример:

var httpCall1 = $http.get('/api/something', {data: params}) 
    .then(function(val) { 
     return { 
      id: "httpCall1" 
      val: val 
     } 
    }) 
var httpCall2 = $http.get('/api/something-else', {data: params}) 
    .then(function(val) { 
     return { 
      id: "httpCall2" 
      val: val 
     } 
    }) 
// Might want to make a reusable function out of the above two, if you use this in Production 
Promise.race([httpCall1, httpCall2]) 
    .then(function(winningPromise) { 
     console.log('And the winner is ' + winningPromise.id); 
     doSomethingWith(winningPromise.val); 
    }); 

Вы можете либо использовать это с polyfil Promise или look into the q.race that someone's developed for Angular (хотя я не проверял).

+0

у этого могут быть некоторые другие очень полезные приложения, но с этим методом я получаю «случайные» данные (в зависимости от времени, когда обещания должны быть разрешены) вместо самого современного. Поэтому он не отвечает на вопрос, если я чего-то не упускаю. –

Смежные вопросы