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í)行了才知道郁油。通過這種方式涩笤,就能提前獲取到結(jié)果,并處理下一步驟。

Promise使用then作為關(guān)鍵字飒箭,回調(diào)最終結(jié)果。then是整個(gè)Promise設(shè)計(jì)模式的核心窿撬,必須要被實(shí)現(xiàn)严里。另外還有其它幾個(gè)關(guān)鍵字用來表示一個(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)鍵字用來擴(kuò)展诡必,讓代碼可讀性更強(qiáng):

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

finally:無論是遇到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)闆]有寫出反轉(zhuǎn)二叉樹而沒有拿到Google的offer。

上面說的是知名開源庫赂毯,promisekit ,可以再github 搜索到踏志,下面說一說 google 實(shí)現(xiàn)的

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

2. google promises 源碼分析

我讀完 google 的源碼之后凄诞,覺得我讀懂了圆雁,后來我決定仿寫,手抄一份帆谍,在抄寫 的過程中伪朽,才發(fā)現(xiàn),光靠看是不行的汛蝙,其實(shí)有很多地方烈涮,在你不寫的時(shí)候根本沒有真正理解他的含義朴肺,只有寫一遍和刨細(xì)節(jié)的時(shí)候才算真正命名,這個(gè) demo 是我手抄 google 的源碼坚洽,并做了一點(diǎn)小改動(dòng)宇挫,主要是我增加了一個(gè) thenAsync 分類,他的方法是沒有異步回調(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)來區(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ì)的看每一行代碼來了解作者的用意,可以看到埃脏,他先創(chuàng)建了一個(gè)新的 promise 然后直接返回了 FBLPromise *promise = [[FBLPromise alloc] initPending]; 然后將當(dāng)前的 promise 也就是 self搪锣,加到了別的地方存起來了秋忙,也就是調(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,后面的場景就用到這個(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)我們通過 fullfill 返回value給調(diào)用者的時(shí)候,他沒有給我們返回一個(gè)正常的值力惯,而是一個(gè)新的promise碗誉,其實(shí)就是相當(dāng)于遞歸了,那么怎么辦?可見父晶,有調(diào)用了上面的 observeOnQueue 方法哮缺,就是我上面說的,有可能調(diào)用兩遍甲喝,然后通過狀態(tài)判斷蝴蜓,就算不是pending狀態(tà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è)東西要想用語言表達(dá)清楚還真的很難豹芯,還是建議自己看源碼

then

相當(dāng)于事件的傳遞,值的傳遞驱敲,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];
}


從代碼里面可以看到,調(diào)用的還是上面的兩個(gè)方法众眨,一定要注意上面的代碼握牧,每次返回的其實(shí)都是一個(gè)新的 promise 容诬, 他是怎么做到 then 的?是先將 self 也就是當(dāng)前的 promise 加到之前的緩存中沿腰,如果之前fullfill也沒關(guān)系览徒,直接調(diào)用fullfill返回就行了,然后通過判斷和截獲颂龙,給新的promise賦值,這樣就能一直傳遞下去了措嵌,實(shí)在是太巧妙了友雳,后面你會(huì)發(fā)現(xiàn),他所有的方法铅匹,都是通過這兩段代碼實(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,來告訴我绍填,當(dāng)前這個(gè)async promise 是否結(jié)束了霎桅,如果你返回給我一個(gè)promise 沒關(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è)就比較見到了,同樣調(diào)用那兩個(gè)方法旋恼,然后只關(guān)心 reject吏口,來捕獲 error

all

所有傳進(jìn)來 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)來的數(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è)值

接下來分別將這些promise再次加入到緩存中鸦难,相當(dāng)于副本吧,當(dāng)我們傳進(jìn)來的某個(gè)promise fullfill或者 reject员淫,這里都會(huì)有相應(yīng)合蔽,每次相應(yīng)的時(shí)候我們都判斷下,所有的promise是否還有沒有fullfill的介返,如果有拴事,那么就代表有promise沒有執(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)來額promise的value的集合步淹,
那么如果有一個(gè) reject了呢从隆?也沒關(guān)系,上面的 fullfill會(huì)回調(diào)一次,這里的 reject也會(huì)回調(diào)一次互亮,為什么呢恒傻?翻到上面看 reject那個(gè)方法,里面有狀態(tài)判斷辛燥,當(dāng)回調(diào)了一次之后,state就不是pending,下次在回調(diào)N次也沒有關(guān)系挎塌,不會(huì)再次通知了徘六,說明都是以第一次為準(zhǔ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<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)來的 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)來十個(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多次啊窃判,別忘了上面我說的,有狀態(tài)攔截喇闸,是不是很奇妙袄琳?

Recover

就是補(bǔ)救的意思,這里發(fā)現(xiàn)有錯(cuò)誤之后燃乍,會(huì)通過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ù)英古,如果沒有執(zhí)行完畢淀衣,那么就會(huì)被group一直強(qiáng)引用這,當(dāng)執(zhí)行完了召调,就會(huì)被釋放膨桥,太有味道了這代碼

Validate

檢測 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é)

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市办素,隨后出現(xiàn)的幾起案子角雷,更是在濱河造成了極大的恐慌,老刑警劉巖性穿,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勺三,死亡現(xiàn)場離奇詭異,居然都是意外死亡需曾,警方通過查閱死者的電腦和手機(jī)吗坚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呆万,“玉大人商源,你說我怎么就攤上這事∧奔酰” “怎么了牡彻?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長出爹。 經(jīng)常有香客問我庄吼,道長,這世上最難降的妖魔是什么严就? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任霸褒,我火速辦了婚禮,結(jié)果婚禮上盈蛮,老公的妹妹穿的比我還像新娘废菱。我一直安慰自己技矮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布殊轴。 她就那樣靜靜地躺著衰倦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪旁理。 梳的紋絲不亂的頭發(fā)上樊零,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音孽文,去河邊找鬼驻襟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛芋哭,可吹牛的內(nèi)容都是我干的沉衣。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼减牺,長吁一口氣:“原來是場噩夢啊……” “哼豌习!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拔疚,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤肥隆,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后稚失,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栋艳,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年句各,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吸占。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诫钓,死狀恐怖旬昭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情菌湃,我是刑警寧澤问拘,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站惧所,受9級(jí)特大地震影響骤坐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜下愈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一纽绍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧势似,春花似錦拌夏、人聲如沸僧著。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盹愚。三九已至,卻和暖如春站故,著一層夾襖步出監(jiān)牢的瞬間皆怕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國打工西篓, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愈腾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓岂津,卻偏偏與公主長得像虱黄,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子寸爆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348