Как проверить, решено ли обещание Angular $q
Я понимаю, что обычно при использовании promises можно просто добавить код продолжения с вызовом then()
и цепочкой.
Тем не менее, я хочу начать асинхронный вызов с завершением обещания, а затем отдельно запустить 3-секундный $timeout()
, чтобы я мог принять действие пользовательского интерфейса, ТОЛЬКО, ЕСЛИ оригинальное обещание еще не завершено. (Я ожидаю, что это произойдет только при медленных соединениях, мобильных устройствах на 3G и т.д.).
Учитывая обещание, могу ли я проверить, завершено ли это или нет, без блокировки или ожидания?
Ответы
Ответ 1
Я предполагаю, что это было добавлено в последней версии Angular, но, похоже, теперь есть объект состояния $$ по обещанию:
var deferred = $q.defer();
console.log(deferred.promise.$$state.status); // 0
deferred.resolve();
console.log(deferred.promise.$$state.status); //1
Как отмечено в комментариях, это не рекомендуется, поскольку это может сломаться при обновлении версии Angular.
Ответ 2
Я думаю, что ваш лучший вариант, как есть (без изменения источника Angular и отправки запроса на перенос), заключается в том, чтобы сохранить локальный флаг, если обещание было разрешено. Reset это каждый раз, когда вы настраиваете обещание, которое вас интересует, и помечайте его как завершенное в then()
для оригинального обещания. В $timeout
then()
установите флажок, чтобы узнать, разрешено ли обещание оригинала или нет.
Что-то вроде этого:
var promiseCompleted = false;
promise.then(function(){promiseCompleted=true;})
$timeout(...).then(function(){if(!promiseCompleted)doStuff()})
Внедрение Kris Kowal включает в себя другие методы проверки состояния обещания, но он выглядит Angular реализация $q
, к сожалению, не включает их.
Ответ 3
Это кажется невозможным, как уже упоминал @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);
Ответ 4
У меня была аналогичная проблема, когда мне нужно было проверить, вернулось ли обещание. Поскольку функция AngularJS $watch
регистрирует изменение при рендеринге страницы, даже если оба новых и старых значения undefined, я должен проверить, есть ли какие-либо данные, которые необходимо хранить в моей внешней модели.
Это, безусловно, взлом, но я делаю это:
$scope.$watch('userSelection', function() {
if(promiseObject.hasOwnProperty("$$v"){
userExportableState.selection = $scope.userSelection;
}
};
Я знаю, что $$v
- внутренняя переменная, используемая AngularJS, но она была достаточно надежной как индикатор разрешенного обещания для нас. Кто знает, что произойдет, когда мы перейдем к AngularJS 1.2: -/Я не вижу упоминания об улучшениях в $q
в документах 1.2, но, возможно, кто-то напишет замену с лучшим набором функций ближе к Q.
Ответ 5
Я не знаю вашего точного сценария, но более типично устанавливать тайм-аут сразу после асинхронного вызова (и генерации обещания).
Предоставление инструкции setTimeout()
в том же потоке событий, что и асинхронный вызов, вам не нужно беспокоиться о возможности действия гонки. Поскольку javascript строго одинарный, обещание .then()
обратных вызовов гарантировано запускается в последнем потоке событий.