84

我知道,在使用 Promise 时,通常只会将延续代码与then()调用和链行为相结合。

但是,我想启动一个 Promise 包装的异步调用,然后单独启动 3 秒$timeout(),以便我可以采取 UI 操作,前提是原始 Promise 尚未完成。(我预计这只会发生在慢速连接、3G 移动设备等情况下。)

给定一个承诺,我可以在没有阻塞或等待的情况下检查它是否完成?

4

5 回答 5

46

我猜这是在最新版本的 Angular 中添加的,但现在似乎在承诺上有一个 $$state 对象:

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

如评论中所述,不建议这样做,因为它可能会在升级 Angular 版本时中断。

于 2015-04-11T19:56:16.503 回答
36

我认为您最好的选择(不修改 Angular 源代码并提交拉取请求)是保留一个本地标志,以表明承诺是否已解决。每次设置您感兴趣的承诺时重置它,并then()在原始承诺中将其标记为完成。在$timeout then()检查标志以了解原始承诺是否已解决。

像这样的东西:

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

Kris Kowal 的实现包括其他检查承诺状态的方法,但$q不幸的是,Angular 的实现似乎不包括这些。

于 2013-07-26T16:12:08.117 回答
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);
于 2013-07-30T21:31:15.643 回答
1

我有一个类似的问题,我需要检查一个承诺是否已经返回。因为 AngularJS 的$watch函数会在渲染页面时注册更改,即使新旧值都未定义,我必须检查是否有任何数据值得存储在我的外部模型中。

这绝对是一个黑客,但我这样做:

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

我知道这$$v是 AngularJS 使用的内部变量,但它作为我们已解决的承诺的指标非常可靠。谁知道当我们升级到 AngularJS 1.2 时会发生什么:-/ 我没有看到$q1.2 文档中提到任何改进,但也许有人会编写一个替代服务,其功能集更接近 Q。

于 2013-09-17T22:57:35.300 回答
0

我不知道您的确切情况,但更典型的是在进行异步调用(并生成承诺)后立即设置超时。

如果setTimeout()语句与异步调用在同一个事件线程中,您不必担心可能出现竞争效应。由于 javascript 是严格的单线程的,因此承诺的.then()回调保证会在以后的事件线程中触发。

于 2013-07-27T01:19:21.823 回答