我正在开发一个复杂的angularjs应用程序。复杂意味着单个视图可能具有从代码的不同位置查询的多个不同数据源,例如页面部分控制器或指令控制器。有时,其中一些请求可能需要更长的时间才能解决,从而使视图处于某种无效状态。我希望能够显示某种“数据加载”横幅,并禁用用户与视图的交互,直到所有承诺都解决为止。这适用于使用$ q.all()函数的简单屏幕。但是,构建应用程序的方式更多地是以业务逻辑为中心,而不是以数据源为中心。因此,对于更复杂的屏幕,将没有一个地方可以自然地访问所有作出的承诺。在代码中创建这样的地方似乎很麻烦。
我想出了这个解决方案:
angular.module('myApp').service('qConfigurer', function ($q) {
var pending = 0;
var origDefer = $q.defer;
$q.defer = function() {
pending++;
var result = origDefer.apply(arguments);
var origResolve = result.resolve;
var origReject = result.reject;
result.resolve = function() {
pending--;
return origResolve.apply(arguments);
};
result.reject = function() {
pending--;
return origReject.apply(arguments);
};
return result;
};
$q.pending = function() {
return pending;
};
return {};
});
有更少的技巧可以达到相同的目的吗?
您正在做的是修改全局状态,然后将更改侵入$q
,这种AOP可以很容易地使第三方模块插件产生问题,我认为这很危险,它不能让您确定更改的范围,更不用说速度惩罚。
在我看来,您真正想要的是一种资源管理方法,一种try(resource)
来自Java,using(
C#或with
Python的资源管理方式。不幸的是,唯一具有此功能的promise实现是Bluebird,我们在这里使用$ q,所以让我们做一个:)
因此,我们希望有一个基于promise的函数,并且无论结果如何,都将其从计数器中减少一个-在我们的情况下,我们的资源形成一个信号量。
function loading(fn){ // takes a function that returns a promise, put in a service
var args = Array.prototype.slice.call(arguments,1);
return $q.when().then(function(){
loading.counter++; // signal the scope somehow, either by having the counter
// on the scope and accepting it as a param, by a watcher or
// with an emit
}).then(function(){
return fn.apply(null, args); // can add context param if you want for `this`
}).finally(function(){
loading.counter--; // signal just like with the above
});
}
loading.counter = 0;
然后,用法变为:
// you can use it like this
loading(function(){
return myService.apiCall(...);
}).then(function(result){
$scope.a = result;
});
// or like this
loading(myService.apiCall,...).then(function(result){
$scope.b = result;
});
如果在加载函数中放置了显示/隐藏逻辑,事件挂钩,作用域变量或输入参数(我出于个人喜好保留此参数,请在其为零时以及在其为1时执行一些操作) -它会显示/隐藏加载屏幕。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句