Как проверить, разрешено ли обещание Angular $ q


84

Я понимаю, что обычно then()при использовании обещаний можно просто присоединить код продолжения с поведением вызова и цепочки.

Однако я хочу запустить асинхронный вызов, заключенный в обещание, а затем отдельно запустить 3-секундный, $timeout()чтобы я мог выполнить действие пользовательского интерфейса, ТОЛЬКО ЕСЛИ исходное обещание еще не выполнено. (Я предполагаю, что это произойдет только при медленном подключении, мобильных устройствах с 3G и т. Д.)

Учитывая обещание, могу ли я проверить, выполнено ли оно, без блокировки и ожидания?


2
Я открыл вопрос по этому поводу в angular и получил полезный ответ github.com/angular/angular.js/issues/8307#issuecomment-49903373
derekdreery

возможный дубликат stackoverflow.com/questions/27039771/…
mvermand

Ответы:


46

Я предполагаю, что это было добавлено в последней версии Angular, но, похоже, теперь в обещании есть объект состояния $$:

 var deferred = $q.defer();
 console.log(deferred.promise.$$state.status); // 0
 deferred.resolve();
 console.log(deferred.promise.$$state.status); //1 

Как отмечалось в комментариях, это не рекомендуется, так как это может сломаться при обновлении вашей версии Angular.


25
В документах Angular говорится, что $$...свойства использовать не следует. Может быть рискованно при обновлении до более новых версий Angular ...
hgoebl

7
Жаль, что Angular предоставляет свои частные переменные на серебряном блюде. :(
Джексон


2
Но но ... Angular не реализовал эту inspectфункцию. Так что никаких соков для нас, разработчиков Angular. У прототипа обещания его просто нет.
Роберт Коритник

36

Я думаю, что ваш лучший вариант как есть (без изменения источника Angular и отправки запроса на перенос) - сохранить локальный флаг, если обещание было выполнено. Сбрасывайте его каждый раз, когда настраиваете обещание, которое вас интересует, и отмечайте его как выполненное then()для исходного обещания. В $timeout then()чеке флаг , чтобы знать , если оригинальное обещание решить еще или нет.

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

var promiseCompleted = false;
promise.then(function(){promiseCompleted=true;})
$timeout(...).then(function(){if(!promiseCompleted)doStuff()})

Реализация Криса Ковала включает другие методы для проверки состояния обещания, но, похоже, реализация Angular, к $qсожалению, их не включает.


9
Здесь лучше использовать .finally (). Приведенный выше код пометит флаг обещания как истинное только в том случае, если он был успешно разрешен.
Каранвир Канг

8

Это кажется невозможным, как уже упоминал @shaunhusain. Но, может быть, в этом нет необходимости:

// shows stuff from 3s ahead to promise completetion, 
// or does and undoes it in one step if promise completes before
$q.all(promise, $timeout(doStuff, 3000)).then(undoStuff);

а может лучше:

var tooSlow = $timeout(doStuff, 3000);
promise.always(tooSlow.cancel);

1

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

Это определенно взлом, но я делаю вот что:

$scope.$watch('userSelection', function() {
  if(promiseObject.hasOwnProperty("$$v"){
    userExportableState.selection = $scope.userSelection;
  }
};

Я знаю, что $$vэто внутренняя переменная, используемая AngularJS, но она оказалась для нас довольно надежным индикатором выполненного обещания. Кто знает, что произойдет, когда мы обновимся до AngularJS 1.2: - / Я не вижу никаких упоминаний об улучшениях $qв документации 1.2, но, возможно, кто-то напишет замену службы с улучшенным набором функций ближе к Q.


Спасибо, но есть варианты получше, чем использование «частных» участников.
Джексон

0

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

Если setTimeout()оператор находится в том же потоке событий, что и асинхронный вызов, вам не нужно беспокоиться о возможности эффекта гонки. Поскольку javascript является строго однопоточным, .then()обратные вызовы обещания гарантированно сработают в более позднем потоке событий.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.