Как проверить, разрешено ли обещание 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
см. также: stackoverflow.com/questions/27039771/…
mvermand
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сожалению, их не включает.

Shaunhusain
источник
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.

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

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

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

Свекла-свекла
источник