在iOS中咱们通常使用delegate(代理)或者block(闭包)来进行异步操做,当要执行多个异步操做,必须将第二个嵌套在第一个的完成内,而且还要正常处理错误。这使得代码结构异常的混乱,不方便查看。git
相信码过JS
的同窗都清楚,在es6中新增promise
的语法,今后异步操做更加的灵活,它使得回调与事件进行了组合,并且写法优美。谷歌在18年上半年开源了promises库,使iOS上的异步编程更加便捷,其使用方式与JS中的promise
一致,并支持OC与Swift。es6
Promise
表明异步执行的结果或者错误信息。其拥有如下三种状态github
当状态发生变动后,就没法再次变动其状态。同时promise
不限制其订阅者,当状态发生变化后,全部的订阅者都能接收到通知。同时订阅者能够返回另外一个promise
对象,从而造成管道通讯。编程
管道通讯过程能够自由的使用线程swift
从上图中能够得知目前支持的操做,咱们能够在FBLPromise
文件查找Promise
的实现原理api
//三种状态类型
typedef NS_ENUM(NSInteger, FBLPromiseState) {
FBLPromiseStatePending = 0,
FBLPromiseStateFulfilled,
FBLPromiseStateRejected,
};
//闭包的回调类型
typedef void (^FBLPromiseObserver)(FBLPromiseState state, id __nullable resolution);```
复制代码
@implementation FBLPromise {
//当前promise的状态
FBLPromiseState _state;
//存放执行相关逻辑的结果存储
id __nullable _value;
//存放执行相关逻辑的错误
NSError *__nullable _error;
//存放订阅者的信息
NSMutableArray<FBLPromiseObserver> *_observers;
}
复制代码
完成或失败的操做实际上是遍历全部订阅者,将当前的状态和执行后的结果通知订阅者。执行完毕后改变缓存的状态值,就算后期再次调用也不会响应。达到只要状态变动就没法再次启动的效果。promise
- (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); } _observers = nil; dispatch_group_leave(FBLPromise.dispatchGroup); } } } } 复制代码
订阅相关信息时,先去判断当前的状态类型,当此时已经执行完毕后,会立刻回调相关的执行结果。缓存
- (void)observeOnQueue:(dispatch_queue_t)queue fulfill:(FBLPromiseOnFulfillBlock)onFulfill reject:(FBLPromiseOnRejectBlock)onReject { @synchronized(self) { //先判断当前的状态,只有正在执行的过程当中才能够订阅 switch (_state) { case FBLPromiseStatePending: { if (!_observers) { _observers = [[NSMutableArray alloc] init]; } //增长一个闭包,采用闭包的方式保存外部变量环境 [_observers addObject:^(FBLPromiseState state, id __nullable resolution) { dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ switch (state) { case FBLPromiseStatePending: break; case FBLPromiseStateFulfilled: onFulfill(resolution); break; case FBLPromiseStateRejected: onReject(resolution); break; } }); }]; break; } case FBLPromiseStateFulfilled: { dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ onFulfill(self->_value); }); break; } case FBLPromiseStateRejected: { dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ onReject(self->_error); }); break; } } } } 复制代码
此处是整个promise操做的重中之重,也是咱们promise中使用最多的原理所在,从FBLPromise+Then
中能够看出该方法是then
的原理,也是实现管道通讯的原理bash
- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill chainedReject:(FBLPromiseChainedRejectBlock)chainedReject { //建立新的promise FBLPromise *promise = [[FBLPromise alloc] initPending]; //定义执行的闭包,该闭包是管道通讯的精华,也是为何下一个then中能收到当前then中返回promise执行结果的关键 __auto_type resolver = ^(id __nullable value) { //判断then返回的是不是promise if ([value isKindOfClass:[FBLPromise class]]) { //订阅then返回的promise,主要是为了调用下一个then [(FBLPromise *)value observeOnQueue:queue fulfill:^(id __nullable value) { [promise fulfill:value]; } reject:^(NSError *error) { [promise reject:error]; }]; } else { //若返回的不是promise中,则立刻传给下一个then [promise fulfill:value]; } }; //订阅当前的promise [self observeOnQueue:queue fulfill:^(id __nullable value) { //执行then操做后的返回值,多是promise也多是其余值 value = chainedFulfill ? chainedFulfill(value) : value; //调用上面建立的闭包 resolver(value); } reject:^(NSError *error) { id value = chainedReject ? chainedReject(error) : error; resolver(value); }]; return promise; } 复制代码
此处仅展现swift的语法,oc上的使用请参考FBL
前缀的类,或者直接阅读官方文档markdown
默认是在主线程中使用,如需在其余线程中使用,能够设置on: DispatchQueue
,此处不做介绍
let promise = Promise<Int> { fulfill, reject in let vail = true if vail { fulfil(12) }else { reject(error) } } 复制代码
//采用预先定义方式 let promise = Promise<Int>.pending() ... if success { promise.fulfill(12) } else { promise.reject(error) } //直接发起结果的方式 let promise = Promise(12) let promise = Promise(error) 复制代码
let numberPromise = Promise { fulfill, _ in fulfill(42) } let stringPromise = numberPromise.then { number in return Promise { fulfill, _ in fulfill(String(number)) } } typealias Block = (Int) -> [Int] let blockPromise = stringPromise.then { value in return Promise<Block> { fulfill, _ in fulfill({ number in return [number + (Int(value) ?? 0)] }) } } let finalPromise = blockPromise.then { (value: @escaping Block) -> Int? in return value(42).first } let postFinalPromise = finalPromise.then { number in return number ?? 0 } 复制代码
catch是处理promise中出现错误的状况,在promise管道中,当其中一个promise执行出现错误时,会忽略这个以后的管道直接将错误传输到catch中处理。
let promise = Promise<AnyObject> { return error }.catch { error in //处理错误 } 复制代码
只有当all中全部的promise否成功执行后才回调,回调参数未all中全部执行结果的元组,当其中一个调用rejected
时,都直接回调错误
let promise1 = Promise<Int?> { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 1, execute: { fulfill(42) }) } let promise2 = Promise<Int?> { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 2, execute: { fulfill(13) }) } let promise3 = Promise<Int?> { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 3, execute: { fulfill(nil) }) } let combinedPromise = all([promise1, promise2, promise3]).then { value in print(value) //[Optional(42), Optional(13), nil] } 复制代码
不管管道中是顺利成功执行仍是出现错误,最终都会执行always的闭包
var count = 0 let promise = Promise<Void> { _, reject in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 3, execute: { reject(DYError.promise) }) }.always { count += 1 }.catch { error in count += 1 }.always { print(count) } 复制代码
与all
操做类型,可是Any
中即使有其中的出现了错误也会返回元组数据吗,其元组类型是Maybe
,包含error
与value
相关信息
let promise1 = Promise<Int?> { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 3, execute: { fulfill(42) }) } let promise2 = Promise<Int?> { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 2, execute: { fulfill(13) }) } let promise3 = Promise<Int?> { _, reject in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 1, execute: { reject(DYError.promise) }) } let combinedPromise = any([promise1, promise2, promise3]).then { value in let item = value.first print(value.first?.value) } 复制代码
使用该操做,能够同步等待在不一样线程上执行的promise。该语法与ES8中async/await
的使用时相似的
Promise<Int> { let minusFive = try await(calculator.negate(5)) let twentyFive = try await(calculator.multiply(minusFive, minusFive)) let twenty = try await(calculator.add(twentyFive, minusFive)) let five = try await(calculator.subtract(twentyFive, twenty)) let zero = try await(calculator.add(minusFive, five)) return try await(calculator.multiply(zero, five)) }.then { result in }.catch { error in } 复制代码
该操做返回一个预先定义的promise,等到给定的时间后执行,或者当即执行错误
let promise = Promise(42).delay(2) promise.catch { err in print(err) }.then { value in print(value) } DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 1, execute: { promise.reject(DYError.promise) }) 复制代码
该操做与all
类似,可是返回的是先执行完成的promise结果或者错误
let promise1 = Promise<Any?> { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 2, execute: { fulfill(42) }) } let promise2 = Promise<Any?> { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 3, execute: { fulfill("hello world") }) } let promise3 = Promise<Any?> { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 2, execute: { fulfill([44]) }) } let promise4 = Promise<Any?> { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 4, execute: { fulfill(nil) }) } race([promise1,promise2,promise3,promise4]).then { (value) in print(value) } 复制代码
与Catch
效果相同,可是该操做符不会隔断管道中其余promise的执行
let promise = Promise<Int> { _, reject in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 4, execute: { reject(DYError.promise) }) }.recover { error -> Promise<Int> in print(error) return Promise { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 4, execute: { fulfill(1) }) } }.catch { err in print(err) }.then { value in print(value) } 复制代码
结合其余数据进行变换
let numbers = [1, 2, 3] Promise("0").reduce(numbers) { partialString, nextNumber in Promise(partialString + ", " + String(nextNumber)) }.then { string in // Final result = 0, 1, 2, 3 print("Final result = \(string)") } 复制代码
promise执行失败时,尝试从新执行。在未设置时间的前提下,默认延迟1s从新执行
var count = 0 retry(attempts: 3, delay: 5, condition: { (num, error) -> Bool in print("\(num)" + error.localizedDescription) if num == 2 { //立刻执行错误 return false } return true }) { () -> Promise<Int> in return count == 3 ? Promise(42) : Promise(DYError.promise) }.then { (value) in print(value) }.catch { (error) in print(error) } 复制代码
在指定的时间内若是没有执行完成或者发送错误,则自发错误
let promise = Promise { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 4, execute: { fulfill(42) }) }.timeout(1).catch { err in print(err) //timedOut }.then { value in print(value) } 复制代码
判断是否有效,若是无效则自发错误
let promise = Promise { fulfill, _ in DispatchQueue(label: "queue").asyncAfter(deadline: .now() + 4, execute: { fulfill(42) }) }.validate { value in return value == 1 }.catch { err in print(err) //validationFailure }.then { value in print(value) } 复制代码