很多时候作为一个ioser很羡慕人家用promise来控制异步执行函数。
虽然说有promiseKit这种神器 但是总归希望能了解一下promise;
- 何谓promise
A Promise is a proxy for a value not necessarily known when the promise is created.
It allows you to associate handlers with an asynchronous action's eventual success value or failure reason.
This lets asynchronous methods return values like synchronous methods: instead of immediately returning the final value,
the asynchronous method returns a promise to supply the value at some point in the future.
======
pending: initial state, not fulfilled or rejected.
fulfilled: meaning that the operation completed successfully.
rejected: meaning that the operation failed.
这是https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 的介绍。
- 作为iOS 开发。兴许对于promise使用场景有限,但是肯定遇到下面的情况
[nettool getData(^(id data){
// 我还要继续请求根据这个data获取的数据
[nettool getData(^(id data){
// 我还要继续请求根据这个data获取的数据
[nettool getData(^(id data){
// 我还要继续请求根据这个data获取的数据
[nettool getData(^(id data){
// 我还要继续请求根据这个data获取的数据
[nettool getData(^(id data){
// 我还要继续请求根据这个data获取的数据
。。。。
})
})
})
})]
是不是看着很恶心,这就是我们常说的回调地狱。对于写的人来说不觉得,但是对以后某位同事来帮你查bug的时候,我想他会买一把刀吧。
试想一下 如果我们这么写呢?
[QXPromise promise^(Fullfilled fullfilled,Rejected rejected ){
[nettool getData(^(id data){
resolve(data)
// if error
rejected(err)
})]
}].then(^id(id data){
[nettool getData(^(id data){
resolve(data)
})]
}).then(^id(id data){
[nettool getData(^(id data){
resolve(data)
})]
}).then(^id(id data){
[nettool getData(^(id data){
resolve(data)
})]
});
是否觉得眼前一亮呢?
在这里我将会实现这个promise
- 定义promise的三个状态
/**
promise状态
- QXPromiseStatePending: 执行中
- QXPromiseStateResolved: 完成执行
- QXPromiseStateRejected: 已拒绝执行
*/
typedef NS_ENUM(NSUInteger, QXPromiseState) {
QXPromiseStatePending = 0,
QXPromiseStateFullfilled = 1,
QXPromiseStateRejected = 2
};
定义block
typedef id (^QXRunBlock) (id value);
typedef void(^QXFullFilledHandler)(id value);
typedef void(^QXErrorBlock)(NSError *error);
typedef QXErrorBlock RejectHandler;
typedef void(^QXPromiseBlock)(ResolveHandler resolve,RejectHandler reject);
typedef void(^ProgressHandler)(double proportion,id value);
实现类
@interface QXPromise : NSObject
@property(nonatomic) id value;
@property(nonatomic) NSError *error;
@property(nonatomic, copy) QXFullFilledHandler resolveBlock;
@property(nonatomic, copy) RejectHandler rejectBlock;
@property(nonatomic, copy) QXPromiseBlock promiseBlock;
@property(nonatomic, copy) RejectHandler catchBlock;
@property(nonatomic, copy) QXRunBlock thenBlock;
+ (QXPromise *)promise:(QXPromiseBlock)block;
我们开始进行梳理
初始化一个promise
- (instancetype)init:(QXPromiseBlock)initBlock {
self = [super init];
if (self) {
[self configure];
self.promiseBlock = initBlock;
}
self.promiseBlock(self.fullfilledblock,self.rejectedblock)
return self;
}
- (void)configure {
if (self) {
self.state = QXPromiseStatePending;
[self keepAlive];
__weak QXPromise * wSelf = self;
self.fullfilledblock = ^(id value){
__strong QXPromise *sSelf = wSelf;
if (sSelf.state != QXPromiseStatePending) return;
if ([value isKindOfClass:[QXPromise class]]) {
if(((QXPromise *)value).state == QXPromiseStatePending) {
sSelf.nextPromise = value;
}
[(QXPromise *) value addObserver:sSelf forKeyPath:@"state" options:NSKeyValueObservingOptionNew context:nil];
} else {
sSelf.value = value;
sSelf.state = QXPromiseStateFullfilled;
[sSelf loseControl];
}
};
self.rejectBlock = ^(NSError *error){
__strong QXPromise *sSelf = wSelf;
if (sSelf.state != QXPromiseStatePending) return;
sSelf.error = error;
sSelf.state = QXPromiseStateRejected;
};
}
}
我们初始化了这个promise。同时对fullfilled和reject 两个blokc初始化。随后将会执行这个promiseblock;
划重点的来了##
先看我们的fullfilledblock
- 确定返回参数的类型,如果是promise说明还有链需要调用,
- 若是value 说明是返回值该promse也属于调用结束了。进入fullfilled状态,
- 是promise对象的 应该对其进行监听。这里使用了kvo。
4.fullfilled绑定的value会被这个promise持有。这对后面的操作来说很重要。
来看我们的rejectblock
。。。没啥看的。抛出错误 ❌
kvo部分应该属于改promise的核心所在了
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:@"state"]) {
QXPromiseState newSate = [change[NSKeyValueChangeNewKey] unsignedIntegerValue];
if (newSate == QXPromiseStateRejected) {
[object removeObserver:self forKeyPath:@"state"];
if (self.catchBlock) {
self.catchBlock([(QXPromise *) object error]);
self.fullfilledBlock(nil);
} else {
self.rejectBlock([(QXPromise *) object error]);
}
} else if (newSate == QXPromiseStateFullfilled) {
[object removeObserver:self forKeyPath:@"state"];
@try {
id value = nil;
self.valueKeptForRetry = [(QXPromise *)object value];
if (self.thenBlock) {
value = self.thenBlock([(QXPromise *) object value]);
} else {
value = [(QXPromise *) object value];
}
self.thenBlock = nil;
self.fullfilledBlock(value);
} @catch (NSException *exception) {
self.rejectBlock(exception);
} @finally {
}
}
}
}
kvo中会抛出错误,或者判断是否需要继续执行。
是否执行通过thenblock来做,这个地方一会再说。
取到thenblock的返回值 作为下一个fullfilledBlock的参数继续执行。
then
- (QXPromise *(^)(QXRunBlock))then {
__weak QXPromise * wSelf = self;
return ^QXPromise*(QXRunBlock thenBlock){
__weak QXPromise *newPromise = nil;
newPromise = [QXPromise promise:^(fullfilledHandler fullfilled, RejectHandler reject) {
__strong QXPromise *sSelf = wSelf;
resolve(sSelf);
}];
newPromise.thenBlock = thenBlock;
return newPromise;
};
嗯 。。。没了 有时间会写另外一种promise的实现方式。
项目使用还是挺好玩的。
当然还有其他的拓展功能 all catch finally....