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