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