Обещание в сервисе самоотменяется

У меня возникла небольшая проблема с сервисом Angular (1.4). Код примерно такой:

    service.retrieveStuffFromServer = function() {
        return httpCallFromServer().then(
            function(data) {
                if (Array.isArray(data)) {
                    return data;
                }
                return [];
            }
        );
    };

Я вызываю эту функцию в двух разных контроллерах. В большинстве случаев он работает по назначению, но у меня возникают проблемы в этих условиях:

  • Вызову HTTP требуется время для возврата данных
  • Контроллер A вызывает службу.
  • Контроллер B вызывает службу.
  • Сервис возвращает данные контроллеру A
  • Вызов в контроллере B отменяется. Логика после него никогда не выполняется

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


person lbreakjai    schedule 28.03.2016    source источник
comment
Или вы хотите, чтобы два вызова возвращали один и тот же результат, то есть кэшировались?   -  person dfsq    schedule 28.03.2016
comment
смысл в том, чтобы вызывать служебные данные только один раз с любого контроллера? Почему вызов в контроллере B отменяется и как?   -  person Gonzalo.-    schedule 28.03.2016
comment
Какие части описания этого состояния являются шагами для его достижения, а какая часть — проблемным поведением (и что должно произойти вместо этого)?   -  person Bergi    schedule 29.03.2016
comment
@Bergi, последняя часть шагов - проблемная часть. Что обычно должно произойти, так это то, что служба возвращает данные обоим контроллерам A и B. Вместо этого логика в B не выполняется.   -  person lbreakjai    schedule 29.03.2016
comment
Странно, такого не должно быть. Можете ли вы показать нам свой точный код? Там может быть ошибка. Кроме того, что говорят ваши инструменты разработки, успешно ли выполняется второй запрос на уровне HTTP? У вас есть обработчики ошибок?   -  person Bergi    schedule 29.03.2016
comment
@Bergi, если честно, код angularJS довольно прост, но, как я сказал в другом комментарии, между кодом и устройством есть несколько слоев, которые я не контролирую, и может быть, что там что-то происходит.   -  person lbreakjai    schedule 29.03.2016
comment
@lbreakjai: Даже в простом коде могут быть ошибки :-) Пожалуйста, отредактируйте свой пост, чтобы показать его   -  person Bergi    schedule 29.03.2016
comment
@Bergi, я вставлю соответствующий код завтра утром, как только он будет у меня перед глазами :-) Спасибо, что уделили время!   -  person lbreakjai    schedule 29.03.2016
comment
Вам нужно return перед httpCall, если это реальный код.   -  person jib    schedule 29.03.2016
comment
@Bergi код в исходном сообщении был обновлен, чтобы отразить реальный код. Я просто изменил некоторые имена, чтобы они были более понятными.   -  person lbreakjai    schedule 29.03.2016
comment
@lbreakjai: Хм, вроде нормально (при условии, что это не httpCallFromServer()). Опять же, можете ли вы проверить, есть ли какие-либо ошибки/отказы?   -  person Bergi    schedule 29.03.2016


Ответы (1)


Трудно сказать, почему это просто не работает, но, предположительно, что-то в httpCall() препятствует повторному выполнению того же вызова до завершения 1-го, и отклоняется, если это происходит. Но если вы хотите, чтобы вызов контроллера B делился ответом от активного предыдущего вызова, вы можете кэшировать промис:

function myFunction() {
   if (!myFunction.promise) {
     myFunction.promise = httpCall()
         .then(function(result) { 
             myFunction.promise = undefined;
             return ...
         }, function(err) {
             myFunction.promise = undefined;
             throw err;
         });
    }
    return myFunction.promise;
 }

Это приведет к возврату того же обещания из предыдущего вызова, пока предыдущий вызов все еще не разрешен.

Использование свойства самой функции в качестве кэша — это удобный способ сохранить состояние, логически связанное с самой функцией. Однако вы можете просто использовать любую переменную, определенную вне области myFunction.

person Jamie Treworgy    schedule 28.03.2016
comment
Вероятно, вы хотите throw err, а не return. Или просто используйте .finally вместо этого. - person Bergi; 29.03.2016
comment
Между моментом написания кода и моментом его запуска на Android/iOS происходит несколько шагов и преобразований, и я не видел причин, по которым он ведет себя именно так. Это тоже непросто воспроизвести, и нужно немного повозиться с Чарльзом. Большое спасибо за ваш ответ, я попробую это, как только смогу. - person lbreakjai; 29.03.2016
comment
finally не является частью фактической спецификации промиса, это расширение для конкретной библиотеки. Поскольку я не знаю, какую библиотеку обещаний он использует, если таковая имеется, я решил написать код, который будет работать где угодно. catch было бы хорошо, но не короче. Вы правы насчет возврата ошибки, спасибо, исправлено! - person Jamie Treworgy; 29.03.2016