OCPromise-用OC实现JS的Promise
上篇文章介绍了OCPromise的基本用法,这篇里我将介绍几个扩展方法。git
上篇结尾处提到过,OCPromise的任务都是在子线程上执行的,那么咱们在接收任务结果时,若是须要进行UI的操做时,还须要本身手动切到主线程上,所以我提供了一个将任务结果传递到主线程的回调方法:github
OCPromise *p = Promise(^(resolve _Nonnull resolve, reject _Nonnull reject) { NSLog(@"start new Promise..."); resolve(@123); }); OCPromise *multiply = function(^OCPromise * _Nullable(id _Nonnull value) { return Promise(^(resolve _Nonnull resolve, reject _Nonnull reject) { NSLog(@"calculating %ld x %ld ...", [value longValue], [value longValue]); resolve([NSNumber numberWithLong:[value longValue] * [value longValue]]); }); }); OCPromise *add = function(^OCPromise * _Nullable(id _Nonnull value) { return Promise(^(resolve _Nonnull resolve, reject _Nonnull reject) { NSLog(@"calculating %ld + %ld ...", [value longValue], [value longValue]); resolve([NSNumber numberWithLong:[value longValue] + [value longValue]]); }); }); p.then(multiply).deliverOnMainThread(^(id _Nonnull value) { NSLog(@"1 got value %@ on %@", value, [NSThread currentThread]); }).then(function(^OCPromise * _Nullable(id _Nonnull value) { NSLog(@"2 got value %@ on %@", value, [NSThread currentThread]); return Promise(^(resolve _Nonnull resolve, reject _Nonnull reject) { resolve(@([value longValue] * 10)); }); })).then(add).deliverOnMainThread(^(id _Nonnull value) { NSLog(@"3 got value %@ on %@", value, [NSThread currentThread]); }).then(function(^OCPromise * _Nullable(id _Nonnull value) { NSLog(@"4 got value %@ on %@", value, [NSThread currentThread]); return nil; }));
2020-06-11 16:10:37.224503+0800 OCPromise_Example[56255:2885996] start new Promise...
2020-06-11 16:10:37.224690+0800 OCPromise_Example[56255:2885996] calculating 123 x 123 ...
2020-06-11 16:10:37.224909+0800 OCPromise_Example[56255:2885925] 1 got value 15129 on <NSThread: 0x6000022c85c0>{number = 1, name = main}
2020-06-11 16:10:37.224920+0800 OCPromise_Example[56255:2885996] 2 got value 15129 on <NSThread: 0x60000228a300>{number = 6, name = (null)}
2020-06-11 16:10:37.225055+0800 OCPromise_Example[56255:2885996] calculating 151290 + 151290 ...
2020-06-11 16:10:37.225182+0800 OCPromise_Example[56255:2885996] 4 got value 302580 on <NSThread: 0x60000228a300>{number = 6, name = (null)}
2020-06-11 16:10:37.225188+0800 OCPromise_Example[56255:2885925] 3 got value 302580 on <NSThread: 0x6000022c85c0>{number = 1, name = main}
经过打印结果咱们能够看到一、3都是在主线程执行的,而且主线程的接收并不影响子线程任务结果在任务链中的传递。deliverOnMainThread的实际调用逻辑就是在子线程接收到上一个任务的结果,而后为主线程添加一个异步任务来执行外部回调将结果传出去,并在当前线程继续将任务结果传递给下一个任务。segmentfault
map的做用就是改变上一个任务的结果并传递给下一个任务。这里提供了两种map方法,一种是实例方法:数组
p.then(multiply).map(^id _Nullable(id _Nonnull value) { NSLog(@"got value before map %@", value); return @([value longValue] * 10); }).then(function(^OCPromise * _Nullable(id _Nonnull value) { NSLog(@"got value after map %@", value); return nil; }));
2020-06-11 16:20:59.395731+0800 OCPromise_Example[56282:2892198] start new Promise...
2020-06-11 16:20:59.396130+0800 OCPromise_Example[56282:2892198] calculating 123 x 123 ...
2020-06-11 16:20:59.396406+0800 OCPromise_Example[56282:2892198] got value before map 15129
2020-06-11 16:20:59.396642+0800 OCPromise_Example[56282:2892198] got value after map 151290
这种map方式很好理解,接收到上一个任务的结果以后,执行回调,在回调内针对结果进行处理以后在return回去。这样下一个任务接收到的入参就是已经处理过的值了。promise
另一种是静态方法:网络
OCPromise *map = OCPromise.map(@[p, add, multiply], ^id _Nullable(id _Nonnull value) { return @([value longValue] * 10); }); p.then(map).then(function(^OCPromise * _Nullable(id _Nonnull value) { NSLog(@"got value %@", value); return nil; }));
2020-06-11 16:25:46.242822+0800 OCPromise_Example[56319:2895774] start new Promise...
2020-06-11 16:25:46.243068+0800 OCPromise_Example[56319:2895772] start new Promise...
2020-06-11 16:25:46.243111+0800 OCPromise_Example[56319:2895773] calculating 123 + 123 ...
2020-06-11 16:25:46.243134+0800 OCPromise_Example[56319:2895770] calculating 123 x 123 ...
2020-06-11 16:25:46.243378+0800 OCPromise_Example[56319:2895774] got value (
1230, 2460, 151290
)异步
有没有发现和OCPromise.all很像?没错,OCPromise.map就是OCPromise.all和实例方法map的结合,OCPromise.map会用传进来的任务数组生成一个all promise的对象,而数组内的每一个任务的执行结果都会再调用传入的mapBlock得到一个新的值并最终存到结果数组中。函数
retry顾名思义,就是在任务执行失败(reject)后进行重试。咱们先看下函数定义:学习
OCPromise * retry(OCPromise *ocPromise, uint8_t times, int64_t delay/*ms*/);
入参一共有三个,第一个是须要执行的任务,第二个是重试的次数,第三个是每次重试的间隔时间(注意是毫秒值),返回值是一个OCPromise对象。
函数的定义很好理解,咱们只须要用retry函数建立一个OCPromise对象并对这个对象的执行结果进行监听就行了。
应用场景常见的就是网络请求的重试,下面我用一个模拟的网络请求来举例说明一下retry的用法:ui
- (void)startRequest { NSDictionary *params = @{@"page":@(self.page)}; retry(OCPromise.resolve(params).then(self.requestPageData), 3, 200).then(function(^OCPromise * _Nullable(id _Nonnull value) { NSLog(@"%@", value); return nil; })).catch(^(id _Nonnull value) { NSLog(@"%@", value); }); } - (OCPromise *)requestPageData { return function(^OCPromise * _Nullable(id _Nonnull value) { return Promise(^(resolve _Nonnull resolve, reject _Nonnull reject) { [self requestDataWithParams:value completion:^(id data, NSError *error) { if (error) { reject(error); } else { resolve(data); } }]; }); }); } - (void)requestDataWithParams:(NSDictionary *)params completion:(void (^) (id data, NSError *error))completion { NSLog(@"start request"); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //completion([NSString stringWithFormat:@"response data with request params %@", params], nil); completion(nil, [NSError errorWithDomain:(@"com.ocpromise.response.err") code:30001 userInfo:@{@"description":@"error"}]); }); }
2020-06-11 16:46:55.107129+0800 OCPromise_Example[56431:2909131] start request
2020-06-11 16:46:56.323393+0800 OCPromise_Example[56431:2909131] start request
2020-06-11 16:46:57.624308+0800 OCPromise_Example[56431:2909130] start request
2020-06-11 16:46:58.674446+0800 OCPromise_Example[56431:2909032] Error Domain=com.ocpromise.response.err Code=30001 "(null)" UserInfo={description=error}
咱们用requestDataWithParams函数模拟了一个网络请求,内部用一个延时函数模拟请求的延时,而且返回一个请求失败的结果。而后咱们将这个网络请求包装成一个OCPromise对象requestPageData,当执行startRequest方法时,咱们生成了针对requestPageData的retry函数,并对结果进行监听,当咱们的请求失败了三次以后catch到了最终结果。
以上就是基于OCPromise的基本方法有扩展的一些使用方法。
你们若是感兴趣能够下载这个库,帮忙给找找bug,提提意见,帮助我学习些新的思路或者扩展一下应用场景。感谢!
github:OCPromise