一、前言
最近学习了 Google 的 promises 库,这里记录一下。库的 GitHub 地址: https://github.com/google/promises,方便大家直接阅读源码,提高水平。
为什么引入Promise?
在日常开发中,异步操作是很常见的情况,比如发起网络请求后,处理网络请求的结果一般都是异步操作,我们一般通过block或者delegate来执行异步操作。但是当有多个异步操作需要嵌套执行时,写出的代码结构就会比较混乱,难以阅读,比较容易出bug。
假设有这样的一种场景,播放加密视频时,需要先通过资源ID获取到视频ID,然后进行解密操作,最后拿解密后的结果去请求视频的播放地址或者视频本身,一般写法,代码如下:
// 仅供演示,未考虑引用循环以及错误处理
[self getVideoIDWithAssetResourceID:@"resource-id" complection:^(NSString *videoID) {
[self decryptVideoWithVideoID:videoID complection:^(NSString *decryptResult) {
[self requestVideoDataWithParam:decryptResult complection:^(NSString *videoPlayURLString) {
[self.player setVideoURLString:videoPlayURLString];
}];
}];
}];
使用promises库,可以将代码变为如下写法:
[[[[[FBLPromise do:^id {
return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
[self getVideoIDWithAssetResourceID:@"resource-id" complection:^(NSString *videoID) {
fulfill(videoID);
}];
}];
}] then:^id(NSString *value){
return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
[self decryptVideoWithVideoID:value complection:^(NSString *decryptResult) {
fulfill(decryptResult);
}];
}];
}] then:^id(NSString *value){
return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
[self requestVideoDataWithParam:value complection:^(NSString *videoPlayURLString) {
fulfill(videoPlayURLString);
}];
}];
}] then:^id(NSString *value) {
[self.player setVideoURLString:value];
return value;
}] catch:^(NSError *error) {
NSLog(@"play failed!");
}];
//还可以使用链式调用
FBLPromise.doOn(dispatch_get_main_queue(), ^id {
return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
[self getVideoIDWithAssetResourceID:@"resource-id" complection:^(NSString *videoID) {
fulfill(videoID);
}];
}];
}).then(^id(NSString *value){
return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
[self decryptVideoWithVideoID:value complection:^(NSString *decryptResult) {
fulfill(decryptResult);
}];
}];
}).then(^id(NSString *value){
return [FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) {
[self requestVideoDataWithParam:value complection:^(NSString *videoPlayURLString) {
fulfill(videoPlayURLString);
}];
}];
}).then(^id(NSString *value) {
[self.player setVideoURLString:value];
return value;
}).catch(^(NSError *error) {
NSLog(@"play failed!");
});
如果将相应逻辑转变为同步,则可进一步简化为如下写法:
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
FBLPromise.doOn(queue, ^id {
return [self getVideoIDWithAssetResourceID:@"resource-id"];
}).thenOn(queue, ^id(NSString *value){
return [self decryptVideoWithVideoID:value];
}).thenOn(queue, ^id(NSString *value){
return [self requestVideoDataWithParam:value];
}).thenOn(dispatch_get_main_queue(), ^id(NSString *value) {
[self.player setVideoURLString:value];
return value;
}).catch(^(NSError *error) {
NSLog(@"play failed!");
});
二、Promise 的简介
-
概念
Promise 把每一个异步操作都封装成一个Promise对象,这个Promise对象存储这个异步操作执行完毕的 future 结果。本质上是异步函数(promise)的返回值(future),通过这种方式,就能提前获取到结果,并处理下一步骤。
-
状态迁移
Promise对象的状态:
- pending:任务执行态,状态可能进入下面的 fulfilled 或 rejected 状态。
- fulfilled:任务完成态,promise不能转为任何其他状态,必须有一个值,且此值不能改变。
- rejected:任务拒绝态,promise不能转为任何其他状态,必须有一个原因(reason),且此原因不能改变。
三、Promises 源码分析
先看FBLPromise.h,它提供了暴露给业务方的接口。上文提到了promise的状态,promise.h提供了初始化三种状态的promise实例函数以及由pending转为fulfilled或者rejected状态的函数,同时支持指定回调的派发队列的能力。
/**
Default dispatch queue used for `FBLPromise`, which is `main` if a queue is not specified.
*/
@property(class) dispatch_queue_t defaultDispatchQueue NS_REFINED_FOR_SWIFT;
/**
Creates a pending promise.
*/
+ (instancetype)pendingPromise NS_REFINED_FOR_SWIFT;
/**
Creates a resolved promise.
@param resolution An object to resolve the promise with: either a value or an error.
@return A new resolved promise.
*/
+ (instancetype)resolvedWith:(nullable id)resolution NS_REFINED_FOR_SWIFT;
/**
Synchronously fulfills the promise with a value.
@param value An arbitrary value to fulfill the promise with, including `nil`.
*/
- (void)fulfill:(nullable Value)value NS_REFINED_FOR_SWIFT;
/**
Synchronously rejects the promise with an error.
@param error An error to reject the promise with.
*/
- (void)reject:(NSError *)error NS_REFINED_FOR_SWIFT;
再看FBLPromisePrivate.h,提供库内部使用的接口和定义,它提供了一些回调block的定义、对promise状态监听的响应函数以及用于支持链式调用的函数。
typedef void (^FBLPromiseOnFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseOnRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE("");
typedef id __nullable (^__nullable FBLPromiseChainedFulfillBlock)(Value __nullable value)
NS_SWIFT_UNAVAILABLE("");
typedef id __nullable (^__nullable FBLPromiseChainedRejectBlock)(NSError *error)
NS_SWIFT_UNAVAILABLE("");
/**
Creates a pending promise.
*/
- (instancetype)initPending NS_SWIFT_UNAVAILABLE("");
/**
Creates a resolved promise.
@param resolution An object to resolve the promise with: either a value or an error.
@return A new resolved promise.
*/
- (instancetype)initWithResolution:(nullable id)resolution NS_SWIFT_UNAVAILABLE("");
/**
Invokes `fulfill` and `reject` blocks on `queue` when the receiver gets either fulfilled or
rejected respectively.
*/
- (void)observeOnQueue:(dispatch_queue_t)queue
fulfill:(FBLPromiseOnFulfillBlock)onFulfill
reject:(FBLPromiseOnRejectBlock)onReject NS_SWIFT_UNAVAILABLE("");
/**
Returns a new promise which gets resolved with the return value of `chainedFulfill` or
`chainedReject` blocks respectively. The blocks are invoked when the receiver gets either
fulfilled or rejected. If `nil` is passed to either block arg, the returned promise is resolved
with the same resolution as the receiver.
*/
- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue
chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill
chainedReject:(FBLPromiseChainedRejectBlock)chainedReject NS_SWIFT_UNAVAILABLE("");
接下来看看最重要同时也是精华所在的then
方法:
- (instancetype)initPending {
self = [super init];
if (self) {
dispatch_group_enter(FBLPromise.dispatchGroup);
}
return self;
}
- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work {
return [self onQueue:FBLPromise.defaultDispatchQueue then:work]; //(1)
}
- (FBLPromise *)onQueue:(dispatch_queue_t)queue then:(FBLPromiseThenWorkBlock)work {
NSParameterAssert(queue);
NSParameterAssert(work);
return [self chainOnQueue:queue chainedFulfill:work chainedReject:nil]; //(2)
}
- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue
chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill
chainedReject:(FBLPromiseChainedRejectBlock)chainedReject {
NSParameterAssert(queue);
// 创建一个新的promise对象,用来链式调用或返回结果
FBLPromise *promise = [[FBLPromise alloc] initPending]; //(3)
// 当 self 被 fulfilled 或者 rejected 时,resolver都会调用,所以这里抽离block,避免重复代码;
__auto_type resolver = ^(id __nullable value) {
if ([value isKindOfClass:[FBLPromise class]]) { // (9)
//这里的value是thenBlock返回的,如果返回的是一个promise,则 returnPromise 会添加订阅,当returnPromise 结束,调用新创建的promise的结束方法,如果此时newPromise也有订阅者(被then过),触发newPromise的thenBlock。
[(FBLPromise *)value observeOnQueue:queue
fulfill:^(id __nullable value) {
[promise fulfill:value];
}
reject:^(NSError *error) {
[promise reject:error];
}];
} else {
[promise fulfill:value];
}
};
// 添加订阅,当self被fulfilled,即会触发下面的fulfill回调block,如果 thenBlock(chainedFulfill)存在,则先执行 thenBlock,然后thenBlock重新生成一个value值(value值也可能不会变化,主要还得看thenBlock函数里有没有改变value);接下来把这个重新赋值的value扔给resolverBlock,resolverBlock会把这个新的value给newPromise,newPromise会调用fulfilled方法,如果此时newPromise也有订阅者(被then过),则就会把这个新value传递给下一个newNewPromise ...
[self observeOnQueue:queue
fulfill:^(id __nullable value) {
value = chainedFulfill ? chainedFulfill(value) : value; // (8)
resolver(value);
}
reject:^(NSError *error) {
id value = chainedReject ? chainedReject(error) : error; // (8)
resolver(value);
}];
return promise;
}
// 添加订阅block,当前promise结束时,回调对应的block(onFulfill/onReject)
- (void)observeOnQueue:(dispatch_queue_t)queue
fulfill:(FBLPromiseOnFulfillBlock)onFulfill
reject:(FBLPromiseOnRejectBlock)onReject {
NSParameterAssert(queue);
NSParameterAssert(onFulfill);
NSParameterAssert(onReject);
// 如果添加订阅的时候promise已经结束了,则直接把结果返回给订阅者,即调用onFulfill或onReject。
@synchronized(self) { // (4)
switch (_state) {
// 默认的state,即待处理的事件
case FBLPromiseStatePending: {
// 如果promise对象还没有观察者数组,new一个,因为一个Promise可以被then很多次,即添加多个订阅
if (!_observers) {
_observers = [[NSMutableArray alloc] init];
}
[_observers addObject:^(FBLPromiseState state, id __nullable resolution) {
dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{
switch (state) { // (7)
case FBLPromiseStatePending:
break;
case FBLPromiseStateFulfilled:
onFulfill(resolution);
break;
case FBLPromiseStateRejected:
onReject(resolution);
break;
}
});
}]; // (5)
break;
}
// 当前promise已经结束
case FBLPromiseStateFulfilled: {
dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{
onFulfill(self->_value);
});
break;
}
case FBLPromiseStateRejected: {
dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{
onReject(self->_error);
});
break;
}
}
}
}
// 当完成时,回调所有订阅者
- (void)fulfill:(nullable id)value {
if ([value isKindOfClass:[NSError class]]) {
[self reject:(NSError *)value];
} else {
@synchronized(self) {
if (_state == FBLPromiseStatePending) {
_state = FBLPromiseStateFulfilled;
_value = value;
_pendingObjects = nil;
for (FBLPromiseObserver observer in _observers) {
observer(_state, _value); // (6)
}
_observers = nil;
dispatch_group_leave(FBLPromise.dispatchGroup);
}
}
}
}
// 当完成时,回调所有订阅者
- (void)reject:(NSError *)error {
NSAssert([error isKindOfClass:[NSError class]], @"Invalid error type.");
if (![error isKindOfClass:[NSError class]]) {
// Give up on invalid error type in Release mode.
@throw error; // NOLINT
}
@synchronized(self) {
if (_state == FBLPromiseStatePending) {
_state = FBLPromiseStateRejected;
_error = error;
_pendingObjects = nil;
for (FBLPromiseObserver observer in _observers) {
observer(_state, _error); // (6)
}
_observers = nil;
dispatch_group_leave(FBLPromise.dispatchGroup);
}
}
}
主要的执行步骤已经在上面做了标注。
四、其他能力
-
then
typedef id __nullable (^FBLPromiseThenWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
then:(FBLPromiseThenWorkBlock)work NS_REFINED_FOR_SWIFT;
then可以看做简版的chainOnQueue: chainedFulfill: chainedReject:
,then对应的是chainedFulfill:。如果前面被监听的promise 状态state是fulfilled,才会调用then对应的的FBLPromiseThenWorkBlock,即promise通过决议时才被调用。如果是rejected,则不会走then对应的block。then可以理解成用于捕获前面异步任务的成功fulfilled value
-
catch
typedef void (^FBLPromiseCatchWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)catch:(FBLPromiseCatchWorkBlock)reject NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
catch:(FBLPromiseCatchWorkBlock)reject NS_REFINED_FOR_SWIFT;
catch和then类似,只不过是监听的promise的状态state是rejected时才会调用。
-
always
- (FBLPromise *)always:(FBLPromiseAlwaysWorkBlock)work NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
always:(FBLPromiseAlwaysWorkBlock)work NS_REFINED_FOR_SWIFT;
和catch、then类似,无论监听的promise的状态变为fulfilled还是rejected,always block都会执行
-
async
typedef void (^FBLPromiseFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE("");
typedef void (^FBLPromiseAsyncWorkBlock)(FBLPromiseFulfillBlock fulfill,
FBLPromiseRejectBlock reject) NS_SWIFT_UNAVAILABLE("");
+ (instancetype)async:(FBLPromiseAsyncWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (instancetype)onQueue:(dispatch_queue_t)queue
async:(FBLPromiseAsyncWorkBlock)work NS_REFINED_FOR_SWIFT;
创建一个pending的promise,并且异步执行work block,work block 执行完成后调用 fulfill(value)
。
-
do
typedef id __nullable (^FBLPromiseDoWorkBlock)(void) NS_SWIFT_UNAVAILABLE("");
+ (instancetype)do:(FBLPromiseDoWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work NS_REFINED_FOR_SWIFT;
同async类似,只不过通过直接调用work block来获取value,即work block 需要同步返回 value
-
any
+ (FBLPromise<NSArray *> *)any:(NSArray *)promises NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSArray *> *)onQueue:(dispatch_queue_t)queue
any:(NSArray *)promises NS_REFINED_FOR_SWIFT;
传入一个promise数组,Any会等待所有的promise 状态变为fulfilled或者rejected,只要有一个prmise状态完成,则结果promise状态会被决议成fulfilled,当所有的promise状态都变为rejected时,结果promise状态也变为rejected,error信息同状态最后变为rejected的promise的error相同。
-
all
+ (FBLPromise<NSArray *> *)all:(NSArray *)promises NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise<NSArray *> *)onQueue:(dispatch_queue_t)queue
all:(NSArray *)promises NS_REFINED_FOR_SWIFT;
传入一个promise数组,All会等待所有的promise 状态变为fulfilled,然后按传入promise数组的顺序返回一个value的数组。如果任何一个promise被rejected,则结果promise立刻被rejected。和any类似
-
race
+ (instancetype)race:(NSArray *)promises NS_SWIFT_UNAVAILABLE("");
+ (instancetype)onQueue:(dispatch_queue_t)queue race:(NSArray *)promises NS_REFINED_FOR_SWIFT;
传入一个promise数组,等待第一个结束的promise,结果promise 和 第一个结束的promise 结果相同。
-
await
FOUNDATION_EXTERN id __nullable FBLPromiseAwait(FBLPromise *promise,
NSError **error) NS_REFINED_FOR_SWIFT;
等待promise结束,成功返回结果,失败返回nil,从error字段获取错误信息,会阻塞当前线程。
-
delay
- (FBLPromise *)delay:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
delay:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT;
创建一个pending的new promise,当self状态变为fulfilled,在delay的时间后,new promise状态变为fulfilled,value同self相同,如果self变为rejected,则忽略delay,直接rejected
-
recover
typedef id __nullable (^FBLPromiseRecoverWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)recover:(FBLPromiseRecoverWorkBlock)recovery NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
recover:(FBLPromiseRecoverWorkBlock)recovery NS_REFINED_FOR_SWIFT;
当receiver变为rejected时,返回一个新的promise,代替rejected的promise
-
retry
typedef id __nullable (^FBLPromiseRetryWorkBlock)(void) NS_SWIFT_UNAVAILABLE("");
typedef BOOL (^FBLPromiseRetryPredicateBlock)(NSInteger, NSError *) NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)onQueue:(dispatch_queue_t)queue
retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)attempts:(NSInteger)count
retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)onQueue:(dispatch_queue_t)queue
attempts:(NSInteger)count
retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)attempts:(NSInteger)count
delay:(NSTimeInterval)interval
condition:(nullable FBLPromiseRetryPredicateBlock)predicate
retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE("");
+ (FBLPromise *)onQueue:(dispatch_queue_t)queue
attempts:(NSInteger)count
delay:(NSTimeInterval)interval
condition:(nullable FBLPromiseRetryPredicateBlock)predicate
retry:(FBLPromiseRetryWorkBlock)work NS_REFINED_FOR_SWIFT;
-
创建一个pending的promise,根据work的返回值,变更状态变为fulfilled,如果将要变更rejected,则retry,在所有的retry次数完成后变为rejected。默认retry count 1,interval 1s
-
timeout
- (FBLPromise *)timeout:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
timeout:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT;
返回一个pending promise,等待self结果直到timeout。它或者以self相同的resolution变为fulfilled或者以超时类型的error变为rejected
-
reduce
typedef id __nullable (^FBLPromiseReducerBlock)(Value __nullable partial, id next)
NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)reduce:(NSArray *)items
combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
reduce:(NSArray *)items
combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE("");
基于当前的promise(self)和items数据源,实现reduce功能,当前promise的值为初值,最终返回的promise是数组最后一个Item转换的promise。伪代码FBLPromise *promise = self; promise = promise + item[index]
-
timeout
- (FBLPromise *)timeout:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
timeout:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT;
返回一个pending promise,等待self结果直到timeout。它或者以self相同的resolution变为fulfilled或者以超时类型的error变为rejected
-
validate
typedef BOOL (^FBLPromiseValidateWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)validate:(FBLPromiseValidateWorkBlock)predicate NS_SWIFT_UNAVAILABLE("");
- (FBLPromise *)onQueue:(dispatch_queue_t)queue
validate:(FBLPromiseValidateWorkBlock)predicate NS_REFINED_FOR_SWIFT;
验证promise fulfilled后的value,如果不能通过验证,则reject此promise
网友评论