iOS promise 设计模式,google promises 源码分析

1. promise 模式概念

关于文字概念,网上一堆,这里摘取下别人的话

Promise 设计模式的原理

Promise设计模式把每一个异步操作都封装成一个Promise对象,这个Promise对象就是这个异步操作执行完毕的结果,但是这个结果是可变的,就像薛定谔的猫,只有执行了才知道。通过这种方式,就能提前获取到结果,并处理下一步骤。

Promise使用then作为关键字,回调最终结果。then是整个Promise设计模式的核心,必须要被实现。另外还有其它几个关键字用来表示一个Promise对象的状态:

pending:任务执行中,状态可能进入下面的fullfill或reject两者之一

ufill/resolved:任务完成了,返回结果

reject:任务失败,并返回错误

fullfill与reject的状态都是不可逆转的,保证了结果的唯一性。

除了then,一些对Promeise的实现还有几个关键字用来扩展,让代码可读性更强:

catch:任务失败,处理error

finally:无论是遇到then还是catch分支最终都会执行回调

when:多个异步任务执行完毕之后才会回调

Promise模式的实现

Promise设计模式在IOS/MacOS平台的最佳实践是由大名鼎鼎的homebrew的作者 Max Howell 写的一个支持iOS/MacOS 的异步编程框架 – PromiseKit , 作者的另一个广为人知的趣事是因为没有写出反转二叉树而没有拿到Google的offer。

上面说的是知名开源库,promisekit ,可以再github 搜索到,下面说一说 google 实现的

我看了 google 的源码之后,真的是让我十分惊叹,写的实在太好了,用极少的代码完成极其强大的功能。

2. google promises 源码分析

我读完 google 的源码之后,觉得我读懂了,后来我决定仿写,手抄一份,在抄写 的过程中,才发现,光靠看是不行的,其实有很多地方,在你不写的时候根本没有真正理解他的含义,只有写一遍和刨细节的时候才算真正命名,这个 demo 是我手抄 google 的源码,并做了一点小改动,主要是我增加了一个 thenAsync 分类,他的方法是没有异步回调的,都是 return , 我增加了个 asyns 的回调,其实他那个 也可以做到异步,return 一个新的 异步的 promise 就行了,但我更喜欢block,这样,我可以再 then 之后,做很多不建立在promis的前提下的异步操作,做完了之后,调用 block,通知此promise 执行完毕。

2.1 promise 类都做了什么

/**
 Copyright 2018 Google Inc. All rights reserved.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at:

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

#import "FBLPromisePrivate.h"

/** All states a promise can be in. */
typedef NS_ENUM(NSInteger, FBLPromiseState) {
  FBLPromiseStatePending = 0,
  FBLPromiseStateFulfilled,
  FBLPromiseStateRejected,
};

typedef void (^FBLPromiseObserver)(FBLPromiseState state, id __nullable resolution);

static dispatch_queue_t gFBLPromiseDefaultDispatchQueue;

@implementation FBLPromise {
  /** Current state of the promise. */
  FBLPromiseState _state;
  /**
   Set of arbitrary objects to keep strongly while the promise is pending.
   Becomes nil after the promise has been resolved.
   */
  NSMutableSet *__nullable _pendingObjects;
  /**
   Value to fulfill the promise with.
   Can be nil if the promise is still pending, was resolved with nil or after it has been rejected.
   */
  id __nullable _value;
  /**
   Error to reject the promise with.
   Can be nil if the promise is still pending or after it has been fulfilled.
   */
  NSError *__nullable _error;
  /** List of observers to notify when the promise gets resolved. */
  NSMutableArray *_observers;
}

+ (void)initialize {
  if (self == [FBLPromise class]) {
    gFBLPromiseDefaultDispatchQueue = dispatch_get_main_queue();
  }
}

+ (dispatch_queue_t)defaultDispatchQueue {
  @synchronized(self) {
    return gFBLPromiseDefaultDispatchQueue;
  }
}

+ (void)setDefaultDispatchQueue:(dispatch_queue_t)queue {
  NSParameterAssert(queue);

  @synchronized(self) {
    gFBLPromiseDefaultDispatchQueue = queue;
  }
}

+ (instancetype)pendingPromise {
  return [[self alloc] initPending];
}

+ (instancetype)resolvedWith:(nullable id)resolution {
  return [[self alloc] initWithResolution:resolution];
}

- (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)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);
      }
      _observers = nil;
      dispatch_group_leave(FBLPromise.dispatchGroup);
    }
  }
}

#pragma mark - NSObject

- (NSString *)description {
  if (self.isFulfilled) {
    return [NSString stringWithFormat:@"<%@ %p> Fulfilled: %@", NSStringFromClass([self class]),
                                      self, self.value];
  }
  if (self.isRejected) {
    return [NSString stringWithFormat:@"<%@ %p> Rejected: %@", NSStringFromClass([self class]),
                                      self, self.error];
  }
  return [NSString stringWithFormat:@"<%@ %p> Pending", NSStringFromClass([self class]), self];
}

#pragma mark - Private

- (instancetype)initPending {
  self = [super init];
  if (self) {
    dispatch_group_enter(FBLPromise.dispatchGroup);
  }
  return self;
}

- (instancetype)initWithResolution:(nullable id)resolution {
  self = [super init];
  if (self) {
    if ([resolution isKindOfClass:[NSError class]]) {
      _state = FBLPromiseStateRejected;
      _error = (NSError *)resolution;
    } else {
      _state = FBLPromiseStateFulfilled;
      _value = resolution;
    }
  }
  return self;
}

- (void)dealloc {
  if (_state == FBLPromiseStatePending) {
    dispatch_group_leave(FBLPromise.dispatchGroup);
  }
}

- (BOOL)isPending {
  @synchronized(self) {
    return _state == FBLPromiseStatePending;
  }
}

- (BOOL)isFulfilled {
  @synchronized(self) {
    return _state == FBLPromiseStateFulfilled;
  }
}

- (BOOL)isRejected {
  @synchronized(self) {
    return _state == FBLPromiseStateRejected;
  }
}

- (nullable id)value {
  @synchronized(self) {
    return _value;
  }
}

- (NSError *__nullable)error {
  @synchronized(self) {
    return _error;
  }
}

- (void)addPendingObject:(id)object {
  NSParameterAssert(object);
  
  @synchronized(self) {
    if (_state == FBLPromiseStatePending) {
      if (!_pendingObjects) {
        _pendingObjects = [[NSMutableSet alloc] init];
      }
      [_pendingObjects addObject:object];
    }
  }
}

- (void)observeOnQueue:(dispatch_queue_t)queue
               fulfill:(FBLPromiseOnFulfillBlock)onFulfill
                reject:(FBLPromiseOnRejectBlock)onReject {
  NSParameterAssert(queue);
  NSParameterAssert(onFulfill);
  NSParameterAssert(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;
      }
    }
  }
}

- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue
              chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill
               chainedReject:(FBLPromiseChainedRejectBlock)chainedReject {
  NSParameterAssert(queue);

  FBLPromise *promise = [[FBLPromise alloc] initPending];
  __auto_type resolver = ^(id __nullable value) {
    if ([value isKindOfClass:[FBLPromise class]]) {
      [(FBLPromise *)value observeOnQueue:queue
          fulfill:^(id __nullable value) {
            [promise fulfill:value];
          }
          reject:^(NSError *error) {
            [promise reject:error];
          }];
    } else {
      [promise fulfill:value];
    }
  };
  [self observeOnQueue:queue
      fulfill:^(id __nullable value) {
        value = chainedFulfill ? chainedFulfill(value) : value;
        resolver(value);
      }
      reject:^(NSError *error) {
        id value = chainedReject ? chainedReject(error) : error;
        resolver(value);
      }];
  return promise;
}

@end

@implementation FBLPromise (DotSyntaxAdditions)

+ (instancetype (^)(void))pending {
  return ^(void) {
    return [self pendingPromise];
  };
}

+ (instancetype (^)(id __nullable))resolved {
  return ^(id resolution) {
    return [self resolvedWith:resolution];
  };
}

@end

这个类主要是初始化,和状态的管理,_state 用作状态的管理,然后有个 -(void)fulfill:(id)value- (void)reject:(NSError *)error 的方法,就是成功或者失败的回调,这两个方法里面是根据 state状态来区分的,这个判断很重要,后面的 race 就用到了这个原理,后面race会讲解,这个类,代码的核心在,


- (void)observeOnQueue:(dispatch_queue_t)queue
               fulfill:(FBLPromiseOnFulfillBlock)onFulfill
                reject:(FBLPromiseOnRejectBlock)onReject 

- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue
              chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill
               chainedReject:(FBLPromiseChainedRejectBlock)chainedReject 


- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue
              chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill
               chainedReject:(FBLPromiseChainedRejectBlock)chainedReject {
  NSParameterAssert(queue);

  FBLPromise *promise = [[FBLPromise alloc] initPending];
  __auto_type resolver = ^(id __nullable value) {
    if ([value isKindOfClass:[FBLPromise class]]) {
      [(FBLPromise *)value observeOnQueue:queue
          fulfill:^(id __nullable value) {
            [promise fulfill:value];
          }
          reject:^(NSError *error) {
            [promise reject:error];
          }];
    } else {
      [promise fulfill:value];
    }
  };
  [self observeOnQueue:queue
      fulfill:^(id __nullable value) {
        value = chainedFulfill ? chainedFulfill(value) : value;
        resolver(value);
      }
      reject:^(NSError *error) {
        id value = chainedReject ? chainedReject(error) : error;
        resolver(value);
      }];
  return promise;
}

这两个方法,分别都是干嘛的呢?chainOnQueue 这个方法真的设计的很神奇,你需要仔细的看每一行代码来了解作者的用意,可以看到,他先创建了一个新的 promise 然后直接返回了 FBLPromise *promise = [[FBLPromise alloc] initPending]; 然后将当前的 promise 也就是 self,加到了别的地方存起来了,也就是调用了下一个方法

- (void)observeOnQueue:(dispatch_queue_t)queue
               fulfill:(FBLPromiseOnFulfillBlock)onFulfill
                reject:(FBLPromiseOnRejectBlock)onReject {
  NSParameterAssert(queue);
  NSParameterAssert(onFulfill);
  NSParameterAssert(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;
      }
    }
  }
}

可以看到这里,他根据三种状态,做不同的事,用意何在呢?首先我们看 pending状态,是创建了一个 observer ,然后添加到当前的缓存中去,为什么这么做呢?我们这么想,如果我们把当前的promise 添加到缓存里面两次,那么最后我们fullfill的时候,看上面的代码,就会从缓存中取出所有的observer 然后依次调用block,然后再这个方法的block里面,再对我们添加的promise分别fullfil,后面的场景就用到这个原理了。还是这段代码里面


__auto_type resolver = ^(id __nullable value) {
    if ([value isKindOfClass:[FBLPromise class]]) {
      [(FBLPromise *)value observeOnQueue:queue
          fulfill:^(id __nullable value) {
            [promise fulfill:value];
          }
          reject:^(NSError *error) {
            [promise reject:error];
          }];
    } else {
      [promise fulfill:value];
    }
  };

有个这个,当我们通过 fullfill 返回value给调用者的时候,他没有给我们返回一个正常的值,而是一个新的promise,其实就是相当于递归了,那么怎么办?可见,有调用了上面的 observeOnQueue 方法,就是我上面说的,有可能调用两遍,然后通过状态判断,就算不是pending状态也没事,也会及时回调,这里想做的其实就是,外面调用者的promise状态的变更,fullfill和reject怎么通知到这里,因为我们这里新建的 FBLPromise *promise = [[FBLPromise alloc] initPending];
,是一定要返回的,所以其实这里可以理解为一个递归,加了两次,调用者的新promise 响应的时候,这里也能相应捕获到,然后通知给新的 promise

这个东西要想用语言表达清楚还真的很难,还是建议自己看源码

then

相当于事件的传递,值的传递,promise 的操作的返回值,要能通过 then 一直传递下去


- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work {
  return [self onQueue:FBLPromise.defaultDispatchQueue then:work];
}

- (FBLPromise *)onQueue:(dispatch_queue_t)queue then:(FBLPromiseThenWorkBlock)work {
  NSParameterAssert(queue);
  NSParameterAssert(work);

  return [self chainOnQueue:queue chainedFulfill:work chainedReject:nil];
}


从代码里面可以看到,调用的还是上面的两个方法,一定要注意上面的代码,每次返回的其实都是一个新的 promise , 他是怎么做到 then 的?是先将 self 也就是当前的 promise 加到之前的缓存中,如果之前fullfill也没关系,直接调用fullfill返回就行了,然后通过判断和截获,给新的promise赋值,这样就能一直传递下去了,实在是太巧妙了,后面你会发现,他所有的方法,都是通过这两段代码实现的,真的巧妙

async

异步调用

+ (instancetype)async:(FBLPromiseAsyncWorkBlock)work {
  return [self onQueue:self.defaultDispatchQueue async:work];
}

+ (instancetype)onQueue:(dispatch_queue_t)queue async:(FBLPromiseAsyncWorkBlock)work {
  NSParameterAssert(queue);
  NSParameterAssert(work);

  FBLPromise *promise = [[FBLPromise alloc] initPending];
  dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{
    work(
        ^(id __nullable value) {
          if ([value isKindOfClass:[FBLPromise class]]) {
            [(FBLPromise *)value observeOnQueue:queue
                fulfill:^(id __nullable value) {
                  [promise fulfill:value];
                }
                reject:^(NSError *error) {
                  [promise reject:error];
                }];
          } else {
            [promise fulfill:value];
          }
        },
        ^(NSError *error) {
          [promise reject:error];
        });
  });
  return promise;
}

这里的 async block 里面,又套了两个 block 分别是 fullfill 和 reject,大概意思就是,调用 async 方法,在异步队列里面,调用 work block 给你,这时候,你再这个block 里面做事情,当做完了之后,再调用work block 里面的 fullfill 或者 reject block,来告诉我,当前这个async promise 是否结束了,如果你返回给我一个promise 没关系,我加到缓存里,当你那边的promise结束后,我这边还是同样可以截获到,然后将我当前的 async 的 promise,再次进行 fullfill或者reject,这样之后就可以再次使用 then或者async了,相当于一个事件流,一直串着。

catch

捕获异常



- (FBLPromise *)catch:(FBLPromiseCatchWorkBlock)reject {
  return [self onQueue:FBLPromise.defaultDispatchQueue catch:reject];
}

- (FBLPromise *)onQueue:(dispatch_queue_t)queue catch:(FBLPromiseCatchWorkBlock)reject {
  NSParameterAssert(queue);
  NSParameterAssert(reject);

  return [self chainOnQueue:queue
             chainedFulfill:nil
              chainedReject:^id(NSError *error) {
                reject(error);
                return error;
              }];
}


这个就比较见到了,同样调用那两个方法,然后只关心 reject,来捕获 error

all

所有传进来 promise 都执行完毕了,我才回调给你,所有的promise都成功了,将成功的value合集返回给你,但是有一个promise 失败了,我就回调给你,认为所有都是这个失败,成功或者失败的回调只会调用一次


+ (FBLPromise *)all:(NSArray *)promises {
  return [self onQueue:self.defaultDispatchQueue all:promises];
}

+ (FBLPromise *)onQueue:(dispatch_queue_t)queue all:(NSArray *)allPromises {
  NSParameterAssert(queue);
  NSParameterAssert(allPromises);

  if (allPromises.count == 0) {
    return [[FBLPromise alloc] initWithResolution:@[]];
  }
  NSMutableArray *promises = [allPromises mutableCopy];
  return [FBLPromise
      onQueue:queue
        async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
          for (NSUInteger i = 0; i < promises.count; ++i) {
            id promise = promises[i];
            if ([promise isKindOfClass:self]) {
              continue;
            } else if ([promise isKindOfClass:[NSError class]]) {
              reject(promise);
              return;
            } else {
              [promises replaceObjectAtIndex:i
                                  withObject:[[FBLPromise alloc] initWithResolution:promise]];
            }
          }
          for (FBLPromise *promise in promises) {
            [promise observeOnQueue:queue
                fulfill:^(id __unused _) {
                  // Wait until all are fulfilled.
                  for (FBLPromise *promise in promises) {
                    if (!promise.isFulfilled) {
                      return;
                    }
                  }
                  // If called multiple times, only the first one affects the result.
                  fulfill([promises valueForKey:NSStringFromSelector(@selector(value))]);
                }
                reject:^(NSError *error) {
                  reject(error);
                }];
          }
        }];
}

从代码里面可以看到,首先进行了一个 for 循环,什么意思呢?比如我传进来的数组,[promise1,promise2,error],当发现,你传给我的数据里面有错误,那我就不继续了,直接抛出错误给你,认为所有的promise 都是这个错误,如果是promise类型就不管,如果不是这两个,就新建一个promsie然后他的value就为数组里面这个值

接下来分别将这些promise再次加入到缓存中,相当于副本吧,当我们传进来的某个promise fullfill或者 reject,这里都会有相应,每次相应的时候我们都判断下,所有的promise是否还有没有fullfill的,如果有,那么就代表有promise没有执行完,继续,当所有都promise的时候,fulfill([promises valueForKey:NSStringFromSelector(@selector(value))]); 执行这个,相当于,当前all所属的那个promise 返回了一个value数组,这个数组的值,就是所有传进来额promise的value的集合,
那么如果有一个 reject了呢?也没关系,上面的 fullfill会回调一次,这里的 reject也会回调一次,为什么呢?翻到上面看 reject那个方法,里面有状态判断,当回调了一次之后,state就不是pending,下次在回调N次也没有关系,不会再次通知了,说明都是以第一次为准

是不是觉得太巧妙了

always

- (FBLPromise *)always:(FBLPromiseAlwaysWorkBlock)work {
  return [self onQueue:FBLPromise.defaultDispatchQueue always:work];
}

- (FBLPromise *)onQueue:(dispatch_queue_t)queue always:(FBLPromiseAlwaysWorkBlock)work {
  NSParameterAssert(queue);
  NSParameterAssert(work);

  return [self chainOnQueue:queue
      chainedFulfill:^id(id value) {
        work();
        return value;
      }
      chainedReject:^id(NSError *error) {
        work();
        return error;
      }];
}

不管你成功还是失败,我都通过block告诉你

Any


+ (FBLPromise *)onQueue:(dispatch_queue_t)queue all:(NSArray *)allPromises {
  NSParameterAssert(queue);
  NSParameterAssert(allPromises);

  if (allPromises.count == 0) {
    return [[FBLPromise alloc] initWithResolution:@[]];
  }
  NSMutableArray *promises = [allPromises mutableCopy];
  return [FBLPromise
      onQueue:queue
        async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
          for (NSUInteger i = 0; i < promises.count; ++i) {
            id promise = promises[i];
            if ([promise isKindOfClass:self]) {
              continue;
            } else if ([promise isKindOfClass:[NSError class]]) {
              reject(promise);
              return;
            } else {
              [promises replaceObjectAtIndex:i
                                  withObject:[[FBLPromise alloc] initWithResolution:promise]];
            }
          }
          for (FBLPromise *promise in promises) {
            [promise observeOnQueue:queue
                fulfill:^(id __unused _) {
                  // Wait until all are fulfilled.
                  for (FBLPromise *promise in promises) {
                    if (!promise.isFulfilled) {
                      return;
                    }
                  }
                  // If called multiple times, only the first one affects the result.
                  fulfill([promises valueForKey:NSStringFromSelector(@selector(value))]);
                }
                reject:^(NSError *error) {
                  reject(error);
                }];
          }
        }];
}

和上面的逻辑相似,但是差别在于,刚开始遇到error不会直接返回了,会等所有都结束了,才会进行组合

Await

卡主当前线程进行等待,等待当前传进来的 promise 执行完毕,才会解锁,用的是信号量,记住是卡主当前线程,这个方法在用的时候要小心


id __nullable FBLPromiseAwait(FBLPromise *promise, NSError **outError) {
  assert(promise);

  static dispatch_once_t onceToken;
  static dispatch_queue_t queue;
  dispatch_once(&onceToken, ^{
    queue = dispatch_queue_create("com.google.FBLPromises.Await", DISPATCH_QUEUE_CONCURRENT);
  });
  dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  id __block resolution;
  NSError __block *blockError;
  [promise chainOnQueue:queue
      chainedFulfill:^id(id value) {
        resolution = value;
        dispatch_semaphore_signal(semaphore);
        return value;
      }
      chainedReject:^id(NSError *error) {
        blockError = error;
        dispatch_semaphore_signal(semaphore);
        return error;
      }];
  dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  if (outError) {
    *outError = blockError;
  }
  return resolution;
}

Race

就是赛跑的意思,比如传进来十个 promise,第一个不管不管成功还是失败了,那么就直接返回了,因为这个最快,只会调用一次


+ (instancetype)onQueue:(dispatch_queue_t)queue race:(NSArray *)racePromises {
  NSParameterAssert(queue);
  NSAssert(racePromises.count > 0, @"No promises to observe");

  NSArray *promises = [racePromises copy];
  return [FBLPromise onQueue:queue
                       async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) {
                         for (id promise in promises) {
                           if (![promise isKindOfClass:self]) {
                             fulfill(promise);
                             return;
                           }
                         }
                         // Subscribe all, but only the first one to resolve will change
                         // the resulting promise's state.
                         for (FBLPromise *promise in promises) {
                           [promise observeOnQueue:queue fulfill:fulfill reject:reject];
                         }
                       }];
}

很多人可能疑惑,这里不是for循环吗,那么一定会fullfill或者reject多次啊,别忘了上面我说的,有状态拦截,是不是很奇妙?

Recover

就是补救的意思,这里发现有错误之后,会通过block告诉你此次发生的错误,然后你可以补救,返回给我一个新的值,然后再进行类似于一个递归的调用


- (FBLPromise *)recover:(FBLPromiseRecoverWorkBlock)recovery {
  return [self onQueue:FBLPromise.defaultDispatchQueue recover:recovery];
}

- (FBLPromise *)onQueue:(dispatch_queue_t)queue recover:(FBLPromiseRecoverWorkBlock)recovery {
  NSParameterAssert(queue);
  NSParameterAssert(recovery);

  return [self chainOnQueue:queue
             chainedFulfill:nil
              chainedReject:^id(NSError *error) {
                return recovery(error);
              }];
}

也就是在这里


 FBLPromise *promise = [[FBLPromise alloc] initPending];
  __auto_type resolver = ^(id __nullable value) {
    if ([value isKindOfClass:[FBLPromise class]]) {
      [(FBLPromise *)value observeOnQueue:queue
          fulfill:^(id __nullable value) {
            [promise fulfill:value];
          }
          reject:^(NSError *error) {
            [promise reject:error];
          }];
    } else {
      [promise fulfill:value];
    }
  };

recover 你新 return 给我的这个新值,然后在进行补救。

Retry

尝试重试,这个大家应该都能看懂


static void FBLPromiseRetryAttempt(FBLPromise *promise, dispatch_queue_t queue, NSInteger count,
                                   NSTimeInterval interval, FBLPromiseRetryPredicateBlock predicate,
                                   FBLPromiseRetryWorkBlock work) {
  __auto_type retrier = ^(id __nullable value) {
    if ([value isKindOfClass:[NSError class]]) {
      if (count <= 0 || (predicate && !predicate(count, value))) {
        [promise reject:value];
      } else {
        dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{
          FBLPromiseRetryAttempt(promise, queue, count - 1, interval, predicate, work);
        });
      }
    } else {
      [promise fulfill:value];
    }
  };
  id value = work();
  if ([value isKindOfClass:[FBLPromise class]]) {
    [(FBLPromise *)value observeOnQueue:queue fulfill:retrier reject:retrier];
  } else  {
    retrier(value);
  }
}

Timeout

在指定时间内,priomise 是否有返回结果


- (FBLPromise *)timeout:(NSTimeInterval)interval {
  return [self onQueue:FBLPromise.defaultDispatchQueue timeout:interval];
}

- (FBLPromise *)onQueue:(dispatch_queue_t)queue timeout:(NSTimeInterval)interval {
  NSParameterAssert(queue);

  FBLPromise *promise = [[FBLPromise alloc] initPending];
  [self observeOnQueue:queue
      fulfill:^(id __nullable value) {
        [promise fulfill:value];
      }
      reject:^(NSError *error) {
        [promise reject:error];
      }];
  typeof(self) __weak weakPromise = promise;
  dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{
    NSError *timedOutError = [[NSError alloc] initWithDomain:FBLPromiseErrorDomain
                                                        code:FBLPromiseErrorCodeTimedOut
                                                    userInfo:nil];
    [weakPromise reject:timedOutError];
  });
  return promise;
}

这个地方也是运用的很巧妙,用的弱引用技术,如果没有执行完毕,那么就会被group一直强引用这,当执行完了,就会被释放,太有味道了这代码

Validate

检测 fullfill 的值 是否合法,当promise fullfil 之后,我需要检查下,这个值是不是我想要的,如果不是返回错误




- (FBLPromise*)validate:(FBLPromiseValidateWorkBlock)predicate {
  return [self onQueue:FBLPromise.defaultDispatchQueue validate:predicate];
}

- (FBLPromise*)onQueue:(dispatch_queue_t)queue validate:(FBLPromiseValidateWorkBlock)predicate {
  NSParameterAssert(queue);
  NSParameterAssert(predicate);

  FBLPromiseChainedFulfillBlock chainedFulfill = ^id(id value) {
    return predicate(value) ? value :
                              [[NSError alloc] initWithDomain:FBLPromiseErrorDomain
                                                         code:FBLPromiseErrorCodeValidationFailure
                                                     userInfo:nil];
  };
  return [self chainOnQueue:queue chainedFulfill:chainedFulfill chainedReject:nil];
}


总结

虽然写了长篇大论,但是还是感觉没有说明白,因为他的设计真的是很巧妙,我也是品了很久才品明白作者的用心,觉得真的是大牛写的代码太赞了,让我膜拜,到现在还有一处不是特别能揣测作者的用心就是他用个 group是什么目的,我感觉不用也可以啊,谁有什么想法或者能解答我这个疑惑的或者我又什么理解错的欢迎留言讨论,最后说一句,代码太牛了。

你可能感兴趣的:(iOS promise 设计模式,google promises 源码分析)