我知道,在使用promise时,通常只会附加带有then()
调用和链行为的延续代码。
然而,我想启动一个promise包装的异步调用,然后单独启动一个3秒的$timeout()
,这样我就可以执行UI操作,前提是原始promise尚未完成。(我预计这只会发生在慢速连接、3G移动设备等情况下。)
如果有承诺,我可以在不阻塞或等待的情况下检查它是否完整吗?
我想这是在Angular的最新版本中添加的,但现在promise上似乎有一个$$state对象:
var deferred = $q.defer();
console.log(deferred.promise.$$state.status); // 0
deferred.resolve();
console.log(deferred.promise.$$state.status); //1
正如评论中所指出的,不建议这样做,因为在升级Angular版本时可能会中断。
我认为最好的选择是(在不修改Angular源代码和提交pull请求的情况下)保留一个本地标志,以确定promise是否已得到解决。每次设置您感兴趣的承诺时都将其重置,并在原始承诺的then()
中将其标记为完成。在$timeout
then()
中,检查标志以了解原始承诺是否已解决。
类似这样的东西:
var promiseCompleted = false;
promise.then(function(){promiseCompleted=true;})
$timeout(...).then(function(){if(!promiseCompleted)doStuff()})
Kris-Kowal的实现包括其他检查promise状态的方法,但Angular对$q
的实现似乎不包括这些方法。
正如@shunhusain已经提到的那样,这似乎是不可能的。但也许没有必要:
// 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);
我也遇到过类似的问题,需要检查是否返回了promise。因为AngularJS的$watch
函数在呈现页面时会注册更改,即使新值和旧值都未定义,我也必须检查是否有任何数据值得存储在我的外部模型中。
这绝对是一个黑客,但我这样做:
$scope.$watch('userSelection', function() {
if(promiseObject.hasOwnProperty("$$v"){
userExportableState.selection = $scope.userSelection;
}
};
我知道$$v
是AngularJS使用的一个内部变量,但它对我们来说是一个非常可靠的指标。谁知道当我们升级到AngularJS 1.2时会发生什么://我在1.2文档中没有看到任何关于$q
的改进,但也许有人会写一个替代服务,它的功能集更接近Q。
我不知道你的确切场景,但更常见的是在进行异步调用(并生成promise)后立即设置超时。
如果setTimeout()
语句与异步调用在同一事件线程中,则不必担心竞争效应的可能性。由于javascript严格来说是单线程的,promise的.then()
回调保证会在以后的事件线程中触发。