@bornkiller
2015-12-20T16:53:37.000000Z
字数 1649
阅读 2140
angularjs
众所周知,promise
只会完成一次状态转换,即不会从resolve
状态变为reject
状态,通过then
函数来执行变相回调。在之前的应用中,自以为是的认为同一个promise
只能调用一次then
方法,偶然才发现单个promise
可以多次利用,实为惭愧。测试代码如下:
var defer = $q.defer()
, promise = defer.promise;
promise.then(function(message) {
console.log(message);
return promise;
}).then(function(message) {
console.log(message);
return promise;
}).then(function(message) {
console.log(message);
});
$timeout(function() {
defer.resolve('hello world');
}, 200);
在then
方法回调函数内部,如果throw error
, then
方法则返回reject
状态的promise
,如果为普通值或无返回值,猜测then
方法会返回通过$q.when
类似方法包装为promise
,如果直接return promise
,则then
方法直接返回该promise
。测试代码中,return
皆为同一个promise
,可以多次通过then
方法调用,类似于一次包装,多次分发,这是包装`$q``服务的前提。
之前需求中需要多次传递highcharts
点击事件,由于highchart-ng
封装没有提供对应的传递方式,所有配置项通过service
完成,controller
中不适宜直接绑定回调,然后通过$scope.$apply
方式来刷新视图,所以想到通过promise
的多次notify
方式来实现,如果不做处理,会出现极其丑陋的代码如下:
// 实际使用方式
promise.then(angular.noop, angular.noop, callback);
// 预期使用方式
promise.notify(callback);
十分不雅。所以可通过包装$q服务的方式来实现,实现如下:
$provide.decorator('$q', function($delegate) {
var defer = $delegate.defer;
$delegate.defer = function() {
var deferred = defer();
deferred.promise.notify = function(callback) {
deferred.promise.then(angular.noop, angular.noop, callback);
return deferred.promise;
};
return deferred;
};
return $delegate;
})
测试效果代码如下:
var defer = $q.defer()
, promise = defer.promise;
promise.notify(function(message) {
console.log(message);
}).then(function(resp) {
console.log(resp);
}).catch(function(errorDesc) {
console.log(errorDesc);
});
$interval(function() {
defer.notify('hello world');
}, 200, 10);
$timeout(function() {
defer.resolve('war never change');
}, 2200);
代码输出10次hello world
,然后正常输出war never change
,表现正常,封装成功。
$http
服务也是基于$q
服务封装而来,success
,error
方法封装方式高度类似,不作赘述。