iOS promise 設(shè)計(jì)模式,google promises 源碼分析

1. promise 模式概念

關(guān)于文字概念,網(wǎng)上一堆,這里摘取下別人的話

Promise 設(shè)計(jì)模式的原理

Promise設(shè)計(jì)模式把每一個(gè)異步操作都封裝成一個(gè)Promise對(duì)象,這個(gè)Promise對(duì)象就是這個(gè)異步操作執(zhí)行完畢的結(jié)果,但是這個(gè)結(jié)果是可變的,就像薛定諤的貓,只有執(zhí)行了才知道。通過(guò)這種方式,就能提前獲取到結(jié)果,并處理下一步驟。

Promise使用then作為關(guān)鍵字,回調(diào)最終結(jié)果。then是整個(gè)Promise設(shè)計(jì)模式的核心,必須要被實(shí)現(xiàn)。另外還有其它幾個(gè)關(guān)鍵字用來(lái)表示一個(gè)Promise對(duì)象的狀態(tài):

pending:任務(wù)執(zhí)行中,狀態(tài)可能進(jìn)入下面的fullfill或reject兩者之一

ufill/resolved:任務(wù)完成了,返回結(jié)果

reject:任務(wù)失敗,并返回錯(cuò)誤

fullfill與reject的狀態(tài)都是不可逆轉(zhuǎn)的,保證了結(jié)果的唯一性。

除了then,一些對(duì)Promeise的實(shí)現(xiàn)還有幾個(gè)關(guān)鍵字用來(lái)擴(kuò)展,讓代碼可讀性更強(qiáng):

catch:任務(wù)失敗,處理error

finally:無(wú)論是遇到then還是catch分支最終都會(huì)執(zhí)行回調(diào)

when:多個(gè)異步任務(wù)執(zhí)行完畢之后才會(huì)回調(diào)

Promise模式的實(shí)現(xiàn)

Promise設(shè)計(jì)模式在IOS/MacOS平臺(tái)的最佳實(shí)踐是由大名鼎鼎的homebrew的作者 Max Howell 寫的一個(gè)支持iOS/MacOS 的異步編程框架 – PromiseKit , 作者的另一個(gè)廣為人知的趣事是因?yàn)闆](méi)有寫出反轉(zhuǎn)二叉樹而沒(méi)有拿到Google的offer。

上面說(shuō)的是知名開源庫(kù),promisekit ,可以再github 搜索到,下面說(shuō)一說(shuō) google 實(shí)現(xiàn)的

我看了 google 的源碼之后,真的是讓我十分驚嘆,寫的實(shí)在太好了,用極少的代碼完成極其強(qiáng)大的功能。

2. google promises 源碼分析

我讀完 google 的源碼之后,覺(jué)得我讀懂了,后來(lái)我決定仿寫,手抄一份,在抄寫 的過(guò)程中,才發(fā)現(xiàn),光靠看是不行的,其實(shí)有很多地方,在你不寫的時(shí)候根本沒(méi)有真正理解他的含義,只有寫一遍和刨細(xì)節(jié)的時(shí)候才算真正命名,這個(gè) demo 是我手抄 google 的源碼,并做了一點(diǎn)小改動(dòng),主要是我增加了一個(gè) thenAsync 分類,他的方法是沒(méi)有異步回調(diào)的,都是 return , 我增加了個(gè) asyns 的回調(diào),其實(shí)他那個(gè) 也可以做到異步,return 一個(gè)新的 異步的 promise 就行了,但我更喜歡block,這樣,我可以再 then 之后,做很多不建立在promis的前提下的異步操作,做完了之后,調(diào)用 block,通知此promise 執(zhí)行完畢。

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<FBLPromiseObserver> *_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

這個(gè)類主要是初始化,和狀態(tài)的管理,_state 用作狀態(tài)的管理,然后有個(gè) -(void)fulfill:(id)value- (void)reject:(NSError *)error 的方法,就是成功或者失敗的回調(diào),這兩個(gè)方法里面是根據(jù) state狀態(tài)來(lái)區(qū)分的,這個(gè)判斷很重要,后面的 race 就用到了這個(gè)原理,后面race會(huì)講解,這個(gè)類,代碼的核心在,


- (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;
}

這兩個(gè)方法,分別都是干嘛的呢?chainOnQueue 這個(gè)方法真的設(shè)計(jì)的很神奇,你需要仔細(xì)的看每一行代碼來(lái)了解作者的用意,可以看到,他先創(chuàng)建了一個(gè)新的 promise 然后直接返回了 FBLPromise *promise = [[FBLPromise alloc] initPending]; 然后將當(dāng)前的 promise 也就是 self,加到了別的地方存起來(lái)了,也就是調(diào)用了下一個(gè)方法

- (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;
      }
    }
  }
}

可以看到這里,他根據(jù)三種狀態(tài),做不同的事,用意何在呢?首先我們看 pending狀態(tài),是創(chuàng)建了一個(gè) observer ,然后添加到當(dāng)前的緩存中去,為什么這么做呢?我們這么想,如果我們把當(dāng)前的promise 添加到緩存里面兩次,那么最后我們fullfill的時(shí)候,看上面的代碼,就會(huì)從緩存中取出所有的observer 然后依次調(diào)用block,然后再這個(gè)方法的block里面,再對(duì)我們添加的promise分別fullfil,后面的場(chǎng)景就用到這個(gè)原理了。還是這段代碼里面


__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];
    }
  };

有個(gè)這個(gè),當(dāng)我們通過(guò) fullfill 返回value給調(diào)用者的時(shí)候,他沒(méi)有給我們返回一個(gè)正常的值,而是一個(gè)新的promise,其實(shí)就是相當(dāng)于遞歸了,那么怎么辦?可見(jiàn),有調(diào)用了上面的 observeOnQueue 方法,就是我上面說(shuō)的,有可能調(diào)用兩遍,然后通過(guò)狀態(tài)判斷,就算不是pending狀態(tài)也沒(méi)事,也會(huì)及時(shí)回調(diào),這里想做的其實(shí)就是,外面調(diào)用者的promise狀態(tài)的變更,fullfill和reject怎么通知到這里,因?yàn)槲覀冞@里新建的 FBLPromise *promise = [[FBLPromise alloc] initPending];
,是一定要返回的,所以其實(shí)這里可以理解為一個(gè)遞歸,加了兩次,調(diào)用者的新promise 響應(yīng)的時(shí)候,這里也能相應(yīng)捕獲到,然后通知給新的 promise

這個(gè)東西要想用語(yǔ)言表達(dá)清楚還真的很難,還是建議自己看源碼

then

相當(dāng)于事件的傳遞,值的傳遞,promise 的操作的返回值,要能通過(guò) 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];
}


從代碼里面可以看到,調(diào)用的還是上面的兩個(gè)方法,一定要注意上面的代碼,每次返回的其實(shí)都是一個(gè)新的 promise , 他是怎么做到 then 的?是先將 self 也就是當(dāng)前的 promise 加到之前的緩存中,如果之前fullfill也沒(méi)關(guān)系,直接調(diào)用fullfill返回就行了,然后通過(guò)判斷和截獲,給新的promise賦值,這樣就能一直傳遞下去了,實(shí)在是太巧妙了,后面你會(huì)發(fā)現(xiàn),他所有的方法,都是通過(guò)這兩段代碼實(shí)現(xiàn)的,真的巧妙

async

異步調(diào)用

+ (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 里面,又套了兩個(gè) block 分別是 fullfill 和 reject,大概意思就是,調(diào)用 async 方法,在異步隊(duì)列里面,調(diào)用 work block 給你,這時(shí)候,你再這個(gè)block 里面做事情,當(dāng)做完了之后,再調(diào)用work block 里面的 fullfill 或者 reject block,來(lái)告訴我,當(dāng)前這個(gè)async promise 是否結(jié)束了,如果你返回給我一個(gè)promise 沒(méi)關(guān)系,我加到緩存里,當(dāng)你那邊的promise結(jié)束后,我這邊還是同樣可以截獲到,然后將我當(dāng)前的 async 的 promise,再次進(jìn)行 fullfill或者reject,這樣之后就可以再次使用 then或者async了,相當(dāng)于一個(gè)事件流,一直串著。

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;
              }];
}


這個(gè)就比較見(jiàn)到了,同樣調(diào)用那兩個(gè)方法,然后只關(guān)心 reject,來(lái)捕獲 error

all

所有傳進(jìn)來(lái) promise 都執(zhí)行完畢了,我才回調(diào)給你,所有的promise都成功了,將成功的value合集返回給你,但是有一個(gè)promise 失敗了,我就回調(diào)給你,認(rèn)為所有都是這個(gè)失敗,成功或者失敗的回調(diào)只會(huì)調(diào)用一次


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

+ (FBLPromise<NSArray *> *)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);
                }];
          }
        }];
}

從代碼里面可以看到,首先進(jìn)行了一個(gè) for 循環(huán),什么意思呢?比如我傳進(jìn)來(lái)的數(shù)組,[promise1,promise2,error],當(dāng)發(fā)現(xiàn),你傳給我的數(shù)據(jù)里面有錯(cuò)誤,那我就不繼續(xù)了,直接拋出錯(cuò)誤給你,認(rèn)為所有的promise 都是這個(gè)錯(cuò)誤,如果是promise類型就不管,如果不是這兩個(gè),就新建一個(gè)promsie然后他的value就為數(shù)組里面這個(gè)值

接下來(lái)分別將這些promise再次加入到緩存中,相當(dāng)于副本吧,當(dāng)我們傳進(jìn)來(lái)的某個(gè)promise fullfill或者 reject,這里都會(huì)有相應(yīng),每次相應(yīng)的時(shí)候我們都判斷下,所有的promise是否還有沒(méi)有fullfill的,如果有,那么就代表有promise沒(méi)有執(zhí)行完,繼續(xù),當(dāng)所有都promise的時(shí)候,fulfill([promises valueForKey:NSStringFromSelector(@selector(value))]); 執(zhí)行這個(gè),相當(dāng)于,當(dāng)前all所屬的那個(gè)promise 返回了一個(gè)value數(shù)組,這個(gè)數(shù)組的值,就是所有傳進(jìn)來(lái)額promise的value的集合,
那么如果有一個(gè) reject了呢?也沒(méi)關(guān)系,上面的 fullfill會(huì)回調(diào)一次,這里的 reject也會(huì)回調(diào)一次,為什么呢?翻到上面看 reject那個(gè)方法,里面有狀態(tài)判斷,當(dāng)回調(diào)了一次之后,state就不是pending,下次在回調(diào)N次也沒(méi)有關(guān)系,不會(huì)再次通知了,說(shuō)明都是以第一次為準(zhǔn)

是不是覺(jué)得太巧妙了

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;
      }];
}

不管你成功還是失敗,我都通過(guò)block告訴你

Any


+ (FBLPromise<NSArray *> *)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不會(huì)直接返回了,會(huì)等所有都結(jié)束了,才會(huì)進(jìn)行組合

Await

卡主當(dāng)前線程進(jìn)行等待,等待當(dāng)前傳進(jìn)來(lái)的 promise 執(zhí)行完畢,才會(huì)解鎖,用的是信號(hào)量,記住是卡主當(dāng)前線程,這個(gè)方法在用的時(shí)候要小心


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

就是賽跑的意思,比如傳進(jìn)來(lái)十個(gè) promise,第一個(gè)不管不管成功還是失敗了,那么就直接返回了,因?yàn)檫@個(gè)最快,只會(huì)調(diào)用一次


+ (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循環(huán)嗎,那么一定會(huì)fullfill或者reject多次啊,別忘了上面我說(shuō)的,有狀態(tài)攔截,是不是很奇妙?

Recover

就是補(bǔ)救的意思,這里發(fā)現(xiàn)有錯(cuò)誤之后,會(huì)通過(guò)block告訴你此次發(fā)生的錯(cuò)誤,然后你可以補(bǔ)救,返回給我一個(gè)新的值,然后再進(jìn)行類似于一個(gè)遞歸的調(diào)用


- (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 給我的這個(gè)新值,然后在進(jìn)行補(bǔ)救。

Retry

嘗試重試,這個(gè)大家應(yīng)該都能看懂


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

在指定時(shí)間內(nèi),priomise 是否有返回結(jié)果


- (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;
}

這個(gè)地方也是運(yùn)用的很巧妙,用的弱引用技術(shù),如果沒(méi)有執(zhí)行完畢,那么就會(huì)被group一直強(qiáng)引用這,當(dāng)執(zhí)行完了,就會(huì)被釋放,太有味道了這代碼

Validate

檢測(cè) fullfill 的值 是否合法,當(dāng)promise fullfil 之后,我需要檢查下,這個(gè)值是不是我想要的,如果不是返回錯(cuò)誤




- (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];
}


總結(jié)

雖然寫了長(zhǎng)篇大論,但是還是感覺(jué)沒(méi)有說(shuō)明白,因?yàn)樗脑O(shè)計(jì)真的是很巧妙,我也是品了很久才品明白作者的用心,覺(jué)得真的是大牛寫的代碼太贊了,讓我膜拜,到現(xiàn)在還有一處不是特別能揣測(cè)作者的用心就是他用個(gè) group是什么目的,我感覺(jué)不用也可以啊,誰(shuí)有什么想法或者能解答我這個(gè)疑惑的或者我又什么理解錯(cuò)的歡迎留言討論,最后說(shuō)一句,代碼太牛了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容