PromiseKit源码分析

作者: 充满活力的早晨 | 来源:发表于2018-08-21 15:04 被阅读38次

    废话不多说,本博就开工。

    源码地址
    本博客没有关注swift ,因此还是采用oc方式分析源码,源码来自pod 更新

    pod 'PromiseKit', '~> 1.0'
    

    概述

    promise 是用来处理回调地狱的,借鉴图


    image

    基本使用

    本文看alert 的promise

        UIAlertView * alertview=[[UIAlertView alloc]initWithTitle:@"alert" message:@"promiseTest" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
        [alertview promise].then(^{
            NSLog(@"dddd");
        });
    

    结果呢


    image.png

    这是怎么实现的呢?进入正题。


    promise 源码实现

    引出核心代码

    @interface PMKAlertViewDelegater : NSObject <UIAlertViewDelegate> {
    @public
        void (^fulfiller)(id);
    }
    @end
    
    
    @implementation PMKAlertViewDelegater
    
    - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
        fulfiller(PMKManifold(@(buttonIndex), alertView));
        PMKRelease(self);
    }
    
    @end
    
    @implementation UIAlertView (PromiseKit)
    
    - (PMKPromise *)promise {
        PMKAlertViewDelegater *d = [PMKAlertViewDelegater new];
        PMKRetain(d);
        self.delegate = d;
        [self show];
        return [PMKPromise new:^(id fulfiller, id rejecter){
            d->fulfiller = fulfiller;
        }];
    }
    
    @end
    

    从上面我们UIAlertView Category 中我们能看出来,这里调用- (PMKPromise *)promise

    1.我们会创建UIAlertView的一个代理并且Retain

    1. 将对象设置为UIAlertView 的代理
      3.展示Alert
      4.生成一个promise

    这里重点是第四步生成promise。

    这里我们可以看看其他零散的小知识点宏定义

    extern void *PMKManualReferenceAssociatedObject;
    #define PMKRetain(obj)  objc_setAssociatedObject(obj, PMKManualReferenceAssociatedObject, obj, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    #define PMKRelease(obj) objc_setAssociatedObject(obj, PMKManualReferenceAssociatedObject, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    

    这里PMKRetain 都是采用关联引用进行保存对象
    PMKRelease 采用关联引用对对象近视释放 ,成对出现的。

    这里还有个限制参数的宏定义,编译阶段就知道了参数的个数

    #define PMKManifold(...) __PMKManifold(__VA_ARGS__, 3, 2, 1)
    #define __PMKManifold(_1, _2, _3, N, ...) __PMKArrayWithCount(N, _1, _2, _3)
    extern id __PMKArrayWithCount(NSUInteger, ...);
    

    这里 ... 就是用VA_ARGS 代表的,代表无限参数
    怎么看这个宏定义呢?我们就是把参数带人一步步看就知道了

    假设我们的参数是@1 ,@2,@3 这个宏定义运行的结果是 __PMKArrayWithCount(3, @1, @2, @3);可以帮助我们自动获取参数的个数,不过这里最多只支持三个
    1 PMKManifold(@1 ,@2,@3) 转换成__PMKManifold(@1 ,@2,@3,3,2,1) VA_ARGS 换成 @1 ,@2,@3*
    __PMKManifold(@1 ,@2,@3,3,2,1) 转换成 __PMKArrayWithCount(3, @1 ,@2,@3) 这里N 是3

    这是宏定义的二次处理。编译阶段我们就知道参数的个数了。性能能改善一点是一点吧。

    核心源码类PMKPromise

    PMKPromise 类结构

    这个类结构比较简单


    PMKPromise.png
    PMKPromise 类初始化

    看了API 作者没有标记那个是真正的初始化API
    真正生成对象的API是

    + (instancetype)promiseWithResolver:(void (^)(PMKResolver))block 
    

    默认的+init 方法给重写设置无效

    typedef void (^PMKResolver)(id);
    
    + (instancetype)promiseWithResolver:(void (^)(PMKResolver))block {
        PMKPromise *this = [self alloc];
        this->_promiseQueue = PMKCreatePromiseQueue();
        this->_handlers = [NSMutableArray new];
    
        @try {
            block(^(id result){
                if (PMKGetResult(this))
                    return PMKLog(@"PromiseKit: Warning: Promise already resolved");
    
                PMKResolve(this, result);
            });
        } @catch (id e) {
            // at this point, no pointer to the Promise has been provided
            // to the user, so we can’t have any handlers, so all we need
            // to do is set _result. Technically using PMKSetResult is
            // not needed either, but this seems better safe than sorry.
            PMKSetResult(this, NSErrorFromException(e));
        }
    
        return this;
    }
    

    这里我们看传入的参数只有一个PMKResolver类型的block

    1 入参: 传入PMKResolver 类型block
    2 初始化: 创建PMKPromise 对象,分配空间
    3 给PMKPromise 对象 的成员变量_promiseQueue设置值。queue 是一个DISPATCH_QUEUE_CONCURRENT 类型的queue 。(Concurrent Dispatch Queue不过创建多少都没有问题,因为Concurrent Dispatch Queue所使用的线程由系统的XNU内核高效管理,不会影响系统性能。
    这里上个图

    image.png
    4创建 数组给 _handlers 赋值
    5 try catch 调用 PMKResolver 类型的block 。传入的参数是block ,类型是^(id result){}。 调用block 失败了,调用**static NSArray PMKSetResult(PMKPromise this, id result)
    6 返回this

    这里看完好多人肯定一头雾水,这是在干么。其实把,这里是我们只是创建了个PMKPromise ,我们采用了block的保存语句块的功能,将对这个PMKPromise 对象的处理放在了外面。如果外界需要对我处理,那么调用我给你外界的句柄 block。(这里要是传入的参数不对,那么我就直接对这个PMKPromise 做错误处理)

    结构如下


    image.png

    我们先看看要是外界传入的参数block 不合法,我们调用的static NSArray *PMKSetResult(PMKPromise *this, id result)

    static NSArray *PMKSetResult(PMKPromise *this, id result) {
        __block NSArray *handlers;
        result = PMKSanitizeResult(result);
        dispatch_barrier_sync(this->_promiseQueue, ^{
            handlers = this->_handlers;
            this->_result = result;
            this->_handlers = nil;
        });
    
        return handlers;
    }
    

    1 调用PMKSanitizeResult对结果进行处理下,保证结果不是nil。
    2 在promise queue中获取下handle ,将handle处理为nil ,将成员变量_result 赋值(一定不是nil,nil代表这个promise还没有被处理,是promise的一种状态)
    3 返回handles

    这里没有对返回的handle 做处理

    我们看看如何处理PMKPromise,外界调用这个block发生了什么事情

    ^(id result){
                if (PMKGetResult(this))
                    return PMKLog(@"PromiseKit: Warning: Promise already resolved");
    
                PMKResolve(this, result);
            }
    

    1.这里很简单, 调用static id PMKGetResult(PMKPromise this) 判断 PMKPromise 是否有结果,有结果就返回。(具体怎么返回看下面)
    2 如果
    * PMKPromise** 没有设置结果就调用*static void PMKResolve(PMKPromise this, id result) 将结果设置到PMKPromise 的变量_result 中(具体函数分析往下面看)

    先看*static id PMKGetResult(PMKPromise this)

    static id PMKGetResult(PMKPromise *this) {
        __block id result;
        dispatch_sync(this->_promiseQueue, ^{
            result = this->_result;
        });
        return result;
    }
    

    这个很简单,就是获取下PMKPromise 的成员变量 _result的值.不过是同步获取,意思是当前线程中获取下 结果返回。

    再看下*static void PMKResolve(PMKPromise this, id result)

    static void PMKResolve(PMKPromise *this, id result) {
        void (^set)(id) = ^(id r){
            NSArray *handlers = PMKSetResult(this, r);
            for (void (^handler)(id) in handlers)
                handler(r);
        };
    
        if (IsPromise(result)) {
            PMKPromise *next = result;
            dispatch_barrier_sync(next->_promiseQueue, ^{
                id nextResult = next->_result;
                
                if (nextResult == nil) {  // ie. pending
                    [next->_handlers addObject:^(id o){
                        PMKResolve(this, o);
                    }];
                } else
                    set(nextResult);
            });
        } else
            set(result);
    }
    

    这算是对PMKPromise 处理的核心函数了

    1 声明一个 block 命名set 。调用这个set block 。这个block中会先调用PMKSetResult,对这个promise 进行赋值操作,然后在处理所有的handle。(这里根据handle的调用和下文知道也是一个block
    2 这里是个宏定义判断result 是不是promise
    3 result 不是 promise 那么就调用set block
    4 result 是promise,命名为next ,那么获取next这个promise 的 成员变量_result。要是这个promise 还没有设置结果,那么我们next的_handle 成员变量中要保存一个block,这个block是处理this promise的句柄(意思是next 调用set的时候,需要将result 告诉下this)。要是promise 的设置了结果,那么就调用set block

    看到这里我估计好多人只是看懂了函数本身,但是整体没有看懂。因此在做个整体图明晰下


    image.png

    这里举例说明

    类的成员变量
    {
            void (^fulfiller)(id);
            PMKPromise * promiseNext;
        PMKPromise * promiseThis;
    }
    
     promiseThis = [PMKPromise new:^(PMKFulfiller fulfill, PMKRejecter reject) {
            fulfill(promiseNext);
        }];
        
        UIAlertView * alertview=[[UIAlertView alloc]initWithTitle:@"alert" message:@"promiseTest" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"确定", nil];
        [alertview promise].then(^{
           fulfiller(@"nextPromise");
            NSLog(@"%@",promiseThis.value);
        });
    

    这里就知道了。handle 中保存的是所有的其他的依赖结果的promise。不单单是一个。可以是多个。

    这里我们再看看UIAlertView 调用的这个初始化方法

    + (instancetype)new:(void(^)(PMKFulfiller, PMKRejecter))block {
        return [self promiseWithResolver:^(PMKResolver resolve) {
            id rejecter = ^(id error){
                if (error == nil) {
                    error = NSErrorFromNil();
                } else if (IsPromise(error) && [error rejected]) {
                    // this is safe, acceptable and (basically) valid
                } else if (!IsError(error)) {
                    id userInfo = @{NSLocalizedDescriptionKey: [error description], PMKUnderlyingExceptionKey: error};
                    error = [NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:userInfo];
                }
                resolve(error);
            };
    
            id fulfiller = ^(id result){
                if (IsError(result))
                    PMKLog(@"PromiseKit: Warning: PMKFulfiller called with NSError.");
                resolve(result);
            };
    
            block(fulfiller, rejecter);
        }];
    }
    

    .这个函数传入带有两个参数的block 这两个参数也同样是个block 。类型分别吃PMKFulfiller 和 PMKRejecter
    2 这里构建了两个block 。再将两个block(rejecter 和 fulfiller) 传给外界了。
    3 . 要是外界调用 fulfiller block ,调用 PMKResolver 类型block 。从上面的分析我们知道,这个就是promise的正常处理。
    4 .要是外界调用rejecter block,这里检查传入的error 要是nil 就生成一个NSError, 要是传入的error 是promise 并且结果是error ,那么认为合法,要是传入的数据不是error,误入调用rejecter,我们我们将这个error 重新包装成一个NSError 类型的error 调用 PMKResolver 类型的resolve 对error进行处理。

    这里我们看出来,这里对promise的结果又做了区分,rejecter 回调的结果一定是NSError 或者结果是NSError的promise ,而fulfiller 就是正常的结果。

    看到这里我们可以对promise的成员变量做个总结了

    1 dispatch_queue_t _promiseQueue; 这个不用过多解释,就是promise的queue
    NSMutableArray *_handlers; 这个装有 当前promise要是有结果,需要将这个结果传递给其他的promise。
    id _result; 这个结果有几种情况 ,没有值 , NSError,promise和其他id类型对象。(后面还有个PMKError 归类到NSError中)

    这里其实就产生了一个链条


    image.png

    链条的传递必须是链条前端的promise 有结果了,后面的promise才能执行。

    promise状态 函数
    - (BOOL)pending {
        id result = PMKGetResult(self);
        if (IsPromise(result)) {
            return [result pending];
        } else
            return result == nil;
    }
    
    - (BOOL)resolved {
        return PMKGetResult(self) != nil;
    }
    
    - (BOOL)fulfilled {
        id result = PMKGetResult(self);
        return result != nil && !IsError(result);
    }
    
    - (BOOL)rejected {
        id result = PMKGetResult(self);
        return result != nil && IsError(result);
    }
    
    - (id)value {
        id result = PMKGetResult(self);
        if (IsPromise(result))
            return [(PMKPromise *)result value];
        if ([result isKindOfClass:[PMKArray class]])
            return ((PMKArray *)result)[0];
        if (result == PMKNull)
            return nil;
        else
            return result;
    }
    

    这些函数状态函数都是根据result 来做判断的

    1 - (BOOL)pending ,这个状态代表promise有没有被处理过,或者处理后结果还是promise ,但是这个promise 的_result 还是nil。没有被处理过(fulfiller 传入的参数是一个没有被处理过的promise)。
    2** (BOOL)resolved** ,这个代表promise是否被解决了。
    3- (BOOL)fulfilled, 这个代表这个promise 解决的结果是否是正确的
    4 - (BOOL)rejected,这个代表这个promise 解决的结果是不是error
    5 - (id)value, 获取promise的值,这里需要注意,要是promose的result 是 PMKPromise ,需要特殊处理,不是直接返回。

    promise 链条中的其他函数方法
    - (PMKPromise *(^)(id))then;
    - (PMKPromise *(^)(id))thenInBackground;
    - (PMKPromise *(^)(id))catch;
    - (PMKPromise *(^)(void(^)(void)))finally;
    - (PMKPromise *(^)(dispatch_queue_t, id))thenOn;
    - (PMKPromise *(^)(dispatch_queue_t, id))catchOn;
    - (PMKPromise *(^)(dispatch_queue_t, void(^)(void)))finallyOn;
    + (PMKPromise *)promiseWithValue:(id)value;
    

    看上面的函数,要么返回PMKPromise 对象本身,要么返回 返回值是PMKPromise 类型的block。这就是典型的链式调用了。并且我们也能看出来,这些函数类似try catch finally 结构

    我们把他们分类看

    • (PMKPromise *(^)(id))then ;
      typedef PMKPromise *(^PMKResolveOnQueueBlock)(dispatch_queue_t, id block);
    • (PMKResolveOnQueueBlock)thenOn;
      这里 then 函数的返回值是一个block, 传入的参数是 block,返 回值是PMKPromise
      而thenOn 返回的返回值也是一个block,不过参数是两个,一个是dispatch_queue_t ,第二个是block
    - (PMKPromise *(^)(id))then {
        return ^(id block){
            return self.thenOn(dispatch_get_main_queue(), block);
        };
    }
    

    then函数调用thenOn 线程传入的是主线程。
    重点看thenOn

    - (PMKResolveOnQueueBlock)thenOn {
        return [self resolved:^(id result) {
            if (IsPromise(result))
                return ((PMKPromise *)result).thenOn;
    
            if (IsError(result)) return ^(dispatch_queue_t q, id block) {
                return [PMKPromise promiseWithValue:result];
            };
    
            return ^(dispatch_queue_t q, id block) {
    
                // HACK we seem to expose some bug in ARC where this block can
                // be an NSStackBlock which then gets deallocated by the time
                // we get around to using it. So we force it to be malloc'd.
                block = [block copy];
    
                return dispatch_promise_on(q, ^{
                    return pmk_safely_call_block(block, result);
                });
            };
        }
        pending:^(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolve)(id)) {
            if (IsError(result))
                PMKResolve(next, result);
            else dispatch_async(q, ^{
                resolve(pmk_safely_call_block(block, result));
            });
        }];
    }
    

    这里只调用了一个函数
    *- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
    pending:(void(^)(id result, PMKPromise next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback

    传入给这个函数的两个值在介绍上面的这个函数时候介绍

    - (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
           pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback
    {
        __block PMKResolveOnQueueBlock callBlock;
        __block id result;
        
        dispatch_sync(_promiseQueue, ^{
            if ((result = _result))
                return;
    
            callBlock = ^(dispatch_queue_t q, id block) {
    
                // HACK we seem to expose some bug in ARC where this block can
                // be an NSStackBlock which then gets deallocated by the time
                // we get around to using it. So we force it to be malloc'd.
                block = [block copy];
    
                __block PMKPromise *next = nil;
    
                dispatch_barrier_sync(_promiseQueue, ^{
                    if ((result = _result))
                        return;
    
                    __block PMKPromiseFulfiller resolver;
                    next = [PMKPromise new:^(PMKPromiseFulfiller fulfill, PMKPromiseRejecter reject) {
                        resolver = ^(id o){
                            if (IsError(o)) reject(o); else fulfill(o);
                        };
                    }];
                    [_handlers addObject:^(id value){
                        mkpendingCallback(value, next, q, block, resolver);
                    }];
                });
                
                // next can still be `nil` if the promise was resolved after
                // 1) `-thenOn` read it and decided which block to return; and
                // 2) the call to the block.
    
                return next ?: mkresolvedCallback(result)(q, block);
            };
        });
    
        // We could just always return the above block, but then every caller would
        // trigger a barrier_sync on the promise queue. Instead, if we know that the
        // promise is resolved (since that makes it immutable), we can return a simpler
        // block that doesn't use a barrier in those cases.
    
        return callBlock ?: mkresolvedCallback(result);
    }
    

    1 这个函数的参数有两个,mkresolvedCallback 和 mkpendingCallback。
    2 mkresolvedCallback 参数是个block ,参数是result,返回值是一个PMKResolveOnQueueBlock类型的block,这个类型正好和thenOn的返回值是一个类型。
    3 mkpendingCallback 也是一个block,参数有五个,分别是id类型的result ,PMKPromise类型的next,dispatch_queue_t 类型的q,id类型的block和入参是id 返回值是void的block ,命名是resolver。

    具体分析下这个函数

    1 声明一个变量 callBack 和 result
    2 在promise 的_promiseQueue 同步获取下_result ,要是_result 有结果了,那么调用mkresolvedCallback 入参数是result ,那么就会返回thenOn的所需要的返回类型的值。这里我们看看mkresolvedCallback 执行干了什么事情。需要返回thenOn 中看

    ^(id result) {
            if (IsPromise(result))
                return ((PMKPromise *)result).thenOn;
    
            if (IsError(result)) return ^(dispatch_queue_t q, id block) {
                return [PMKPromise promiseWithValue:result];
            };
    
            return ^(dispatch_queue_t q, id block) {
    
                // HACK we seem to expose some bug in ARC where this block can
                // be an NSStackBlock which then gets deallocated by the time
                // we get around to using it. So we force it to be malloc'd.
                block = [block copy];
    
                return dispatch_promise_on(q, ^{
                    return pmk_safely_call_block(block, result);
                });
            };
        }
    

    这里我们知道传入的result 是当前promise_result 值。
    判断要是 result 是 promise,那么就接着调用 result的thenOn 。
    要是result 是 error,那么我们返回一个PMKResolveOnQueueBlock类型的block,这里需要注意的是执行这个block,直接返回带有result结果的PMKPromise 。(因为是error,block都给抛弃掉了)
    正常的result结果,那我们返回一个PMKResolveOnQueueBlock类型的block。这里需要注意,我们要是执行这个block,那么我们首先要对参数block执行下copy(参数block可能在栈上,被释放),调用PMKPromise dispatch_promise_on(dispatch_queue_t queue, id block) 返回一个PMKpromise.
    这里还有个函数
    id pmk_safely_call_block(id frock, id result)*。这个函数就是对block的解析

    id pmk_safely_call_block(id frock, id result) {
        assert(frock);
    
        if (result == PMKNull)
            result = nil;
    
        @try {
            NSMethodSignature *sig = NSMethodSignatureForBlock(frock);
            const NSUInteger nargs = sig.numberOfArguments;
            const char rtype = sig.methodReturnType[0];
    
            #define call_block_with_rtype(type) ({^type{ \
                switch (nargs) { \
                    case 1: \
                        return ((type(^)(void))frock)(); \
                    case 2: { \
                        const id arg = [result class] == [PMKArray class] ? ((PMKArray *)result)[0] : result; \
                        return ((type(^)(id))frock)(arg); \
                    } \
                    case 3: { \
                        type (^block)(id, id) = frock; \
                        return [result class] == [PMKArray class] \
                            ? block(((PMKArray *)result)[0], ((PMKArray *)result)[1]) \
                            : block(result, nil); \
                    } \
                    case 4: { \
                        type (^block)(id, id, id) = frock; \
                        return [result class] == [PMKArray class] \
                            ? block(((PMKArray *)result)[0], ((PMKArray *)result)[1], ((PMKArray *)result)[2]) \
                            : block(result, nil, nil); \
                    } \
                    default: \
                        @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"PromiseKit: The provided block’s argument count is unsupported." userInfo:nil]; \
                }}();})
    
            switch (rtype) {
                case 'v':
                    call_block_with_rtype(void);
                    return PMKNull;
                case '@':
                    return call_block_with_rtype(id) ?: PMKNull;
                case '*': {
                    char *str = call_block_with_rtype(char *);
                    return str ? @(str) : PMKNull;
                }
                case 'c': return @(call_block_with_rtype(char));
                case 'i': return @(call_block_with_rtype(int));
                case 's': return @(call_block_with_rtype(short));
                case 'l': return @(call_block_with_rtype(long));
                case 'q': return @(call_block_with_rtype(long long));
                case 'C': return @(call_block_with_rtype(unsigned char));
                case 'I': return @(call_block_with_rtype(unsigned int));
                case 'S': return @(call_block_with_rtype(unsigned short));
                case 'L': return @(call_block_with_rtype(unsigned long));
                case 'Q': return @(call_block_with_rtype(unsigned long long));
                case 'f': return @(call_block_with_rtype(float));
                case 'd': return @(call_block_with_rtype(double));
                case 'B': return @(call_block_with_rtype(_Bool));
                case '^':
                    if (strcmp(sig.methodReturnType, "^v") == 0) {
                        call_block_with_rtype(void);
                        return PMKNull;
                    }
                    // else fall through!
                default:
                    @throw PMKE(@"Unsupported method signature… Why not fork and fix?");
            }
        } @catch (id e) {
          #ifdef PMK_RETHROW_LIKE_A_MOFO
            if ([e isKindOfClass:[NSException class]] && (
                [e name] == NSGenericException ||
                [e name] == NSRangeException ||
                [e name] == NSInvalidArgumentException ||
                [e name] == NSInternalInconsistencyException ||
                [e name] == NSObjectInaccessibleException ||
                [e name] == NSObjectNotAvailableException ||
                [e name] == NSDestinationInvalidException ||
                [e name] == NSPortTimeoutException ||
                [e name] == NSInvalidSendPortException ||
                [e name] == NSInvalidReceivePortException ||
                [e name] == NSPortSendException ||
                [e name] == NSPortReceiveException))
                    @throw e;
          #endif
            return NSErrorFromException(e);
        }
    }
    

    这个方法传入的参数有两个,第一个参数是block,第二个参数是返回的结果(链条中上一个promise产生的结果)。
    这个方法是将block 转换成函数签名,通过函数签名方法获取这个block的参数
    static NSMethodSignature *NSMethodSignatureForBlock(id block) 这个方法是对block进行方法解析出签名,将block 转换成函数签名。这样我们就通过这个函数签名知道了这个block的参数以及返回值,知道了参数和返回值,我们就可以自己构造block了。

    PMKPromise *dispatch_promise_on(dispatch_queue_t queue, id block) {
        return [PMKPromise new:^(void(^fulfiller)(id), void(^rejecter)(id)){
            dispatch_async(queue, ^{
                id result = pmk_safely_call_block(block, nil);
                if (IsError(result))
                    rejecter(result);
                else
                    fulfiller(result);
            });
        }];
    }
    

    1.首先明确一点,这个函数返回一个PMKPromise
    2 . 调用+ (instancetype)new:(void(^)(PMKFulfiller, PMKRejecter))block 函数,这个函数前面分析过会给外界执行本fulfiller 和 rejecter 的指针
    3.这里获取到fulfiller 和 rejecter 的指针没有做保留处理,直接执行了。(pmk_safely_call_block 就是对block进行解析执行)
    4 ** pmk_safely_call_block** 执行的block 是 在thenOn(行数323行的block),

                   return pmk_safely_call_block(block, result);
    

    看到这里想明白了就知道了323行的这个block是外界传入的block,result是front 的promise的结果,意思是把front 的promise的结果传递给我们thenOn 后面跟人的block

    到这里,我们分析完毕了要是front 的promise 有结果的回调顺序
    总结下如图


    FlowchartDiagram1.png

    要是front promise 没有结果呢。这说明front promise还没有结果传递过来。
    返回到- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
    pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback函数

    1.生成PMKResolveOnQueueBlock类型的一个block,给callBack赋值。
    2.并且把这个新生成的block返回。暂时标记为block2 。这个block2 接受thenOn传入的的dispatch_queue_t q, id block
    我们看看 block2 干了啥事情
    1 copy 将栈上的block copy到堆上
    2 同步在当前队列上看promise的_result,有_result,直接返回,调用mkresolvedCallback(result)(q, block); 结束。(这里看着有点头大,不过我们分开看就好看了多了,mkresolvedCallback(result) 返回的是PMKResolveOnQueueBlock ,PMKResolveOnQueueBlock执行需要两个参数 dispatch_queue_t q, id block ,因此后面又有两个括号跟着两个参数。其实和刚开始没有参数的逻辑是一样的)
    3 同步在当前队列上看promise的_result ,没有_result .那么我们就重新生成一个PMKpromise 对象,将这个对象返回。这里需要注意的是

     next = [PMKPromise new:^(PMKPromiseFulfiller fulfill, PMKPromiseRejecter reject) {
                        resolver = ^(id o){
                            if (IsError(o)) reject(o); else fulfill(o);
                        };
                    }];
                    [_handlers addObject:^(id value){
                        mkpendingCallback(value, next, q, block, resolver);
                    }];
    

    因为current的promise 还没有结果,所以,我们新生成的next promise 的 Fulfiller 和Rejecter 都不能执行,需要让current promise保存next promise 的Fulfiller 和Rejecter ,当current promise 有结果了,将结果传递给next promise 的Fulfiller 或者Rejecter。
    我们知道,promise链条的传递是通过_handle 来传递的,_handle 中保存的是一个block,类型是^(id value){},参数是current promise的结果,当promise 有结果的时候,会调用_handle中的所有block。因此这里我们需要将next promise 的Fulfiller 和Rejecter 加入到current promise的_handle中去。
    这里我们保存next promise 的fulfiller 和Rejecter 是通过一个block 来保存的。这个block 很简单,参数就一个就是结果了,根据结果选择fulfiller 和Rejecter 执行
    这里我们看看当_handles 里面的block 执行的时候干了什么事情。当block 执行的时候,我们会调用到mkpendingCallback block 这个block 传入的参数比较多,value就是current promise的result , next 就是next Promise ,q 是next 的dispatch_queue_t,block 是thenOn传入的block,resolver 保存的是next 的fulfiller 和Rejecter。
    我们看看mkpendingCallback的实现

    ^(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolve)(id)) {
            if (IsError(result))
                PMKResolve(next, result);
            else dispatch_async(q, ^{
                resolve(pmk_safely_call_block(block, result));
            });
        }
    

    实现很简单了,判断result 是 error ,那么直接更新next promise 的结果,接着传递result 就是了
    要是result不是error,是正常返回值,那么我们切换到next 的的queue中,将result 结果传递到thenOn 传入的block 中(pmk_safely_call_block(block, result)),接着调用resolve block,执行next promise 的fulfiller 和Rejecter。调用结束

    总结下没有结果的情况


    thenOnNotResult.png

    到此,thenOn 的完整代码分析完毕。

    总结下- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
    pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback 这个函数

    1. mkresolvedCallback 当promise 有结果的时候被调用
      2 mkpendingCallback 当promise 没有结果的时候被调用

    接下来看

    - (PMKPromise *(^)(id))catch;
    - (PMKPromise *(^)(dispatch_queue_t, id))catchOn;
    
    - (PMKResolveOnQueueBlock)catchOn {
        return [self resolved:^(id result) {
            if (IsPromise(result))
                return ((PMKPromise *)result).catchOn;
            
            if (IsError(result)) return ^(dispatch_queue_t q, id block) {
    
                // HACK we seem to expose some bug in ARC where this block can
                // be an NSStackBlock which then gets deallocated by the time
                // we get around to using it. So we force it to be malloc'd.
                block = [block copy];
    
                return dispatch_promise_on(q, ^{
                    [PMKError consume:result];
                    return pmk_safely_call_block(block, result);
                });
            };
            
            return ^(dispatch_queue_t q, id block) {
                return [PMKPromise promiseWithValue:result];
            };
        }
        pending:^(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolve)(id)) {
            if (IsError(result)) {
                dispatch_async(q, ^{
                    [PMKError consume:result];
                    resolve(pmk_safely_call_block(block, result));
                });
            } else
                PMKResolve(next, result);
        }];
    }
    

    结构和thenOn 一样,只不过只是调用- (id)resolved:(PMKResolveOnQueueBlock(^)(id result))mkresolvedCallback
    pending:(void(^)(id result, PMKPromise *next, dispatch_queue_t q, id block, void (^resolver)(id)))mkpendingCallback 这个函数 函数传入的block不一样而已

    1 . mkresolvedCallback 样式一样,只不过和thenOn不同的是,对正常数据直接返回了,而对NSerror数据进行处理了,和thenOn正好相反
    2 mkpendingCallback 处理方式相同
    3 其实也可以这么理解,thenOn在promise的链条上只处理正确数据,对错误数据只沿着promise链条传递下去。而catchOn只处理错误数据,对正确的数据,对正确数据不处理,只沿着promise链条传递下去。

    剩下一组,不管正确数据错误数据都处理的api了

    - (PMKPromise *(^)(void(^)(void)))finally;
    - (PMKPromise *(^)(dispatch_queue_t, void(^)(void)))finallyOn;
    
    - (PMKPromise *(^)(dispatch_queue_t, dispatch_block_t))finallyOn {
        return [self resolved:^(id passthru) {
            if (IsPromise(passthru))
                return ((PMKPromise *)passthru).finallyOn;
    
            return ^(dispatch_queue_t q, dispatch_block_t block) {
    
                // HACK we seem to expose some bug in ARC where this block can
                // be an NSStackBlock which then gets deallocated by the time
                // we get around to using it. So we force it to be malloc'd.
                block = [block copy];
    
                return dispatch_promise_on(q, ^{
                    block();
                    return passthru;
                });
            };
        } pending:^(id passthru, PMKPromise *next, dispatch_queue_t q, dispatch_block_t block, void (^resolve)(id)) {
            dispatch_async(q, ^{
                @try {
                    block();
                    resolve(passthru);
                } @catch (id e) {
                    resolve(NSErrorFromException(e));
                }
            });
        }];
    }
    
    1. 这个finallyOn 传入的block 只能是没有参数的block。
      2 返回结果,不对结果做任何处理,。

    这里主要的api 都解决了。看看其他的细节问题

    + (instancetype)promiseWithAdapter:(void (^)(PMKAdapter))block {
        return [self promiseWithResolver:^(PMKResolver resolve) {
            block(^(id value, id error){
                resolve(error ?: value);
            });
        }];
    }
    

    这个 根据外面是否传入error 来判断结果,如果传入error那么我们就将error沿着promise,否则沿着正常数据传递
    还有两个类似的方法

    + (instancetype)promiseWithIntegerAdapter:(void (^)(PMKIntegerAdapter))block {
        return [self promiseWithResolver:^(PMKResolver resolve) {
            block(^(NSInteger value, id error){
                if (error) {
                    resolve(error);
                } else {
                    resolve(@(value));
                }
            });
        }];
    }
    
    + (instancetype)promiseWithBooleanAdapter:(void (^)(PMKBooleanAdapter adapter))block {
        return [self promiseWithResolver:^(PMKResolver resolve) {
            block(^(BOOL value, id error){
                if (error) {
                    resolve(error);
                } else {
                    resolve(@(value));
                }
            });
        }];
    }
    

    以上两个不做介绍,写个小例子,看看就行了

        [PMKPromise promiseWithAdapter:^(PMKAdapter adapter) {
            adapter(@"adapter",nil);
        }].then(^(NSString *str){
            NSLog(@"%@",str);
        });
    
    最多支持三个参数实现

    我们知道我们在调用promise 的fulfiller 或者是rejecter 的时候传入的参数是一个,而在Then,Catch 的时候,我们传入的block可以支持最多不超过三个参数,这如何实现的呢?

    其实fulfiller 或者是rejecter 传入的数据要是多个参数的时候,我们是需要将其打包成 PMKArray 数组的,这个数组其实就是current 的result了。在传递到next promise的时候,我们通过id pmk_safely_call_block(id frock, id result) ,解析出next Promise 传入的block的参数,根据参数个数,从 PMKArray数组中依次取出来。

    特殊API

    promiseKit 支持 when 和until 。when 就是当所有的任务执行完毕在执行我。我们看看如何实现的when

    + (PMKPromise *)when:(id)promises {
        if ([promises conformsToProtocol:@protocol(NSFastEnumeration)]) {
            return [self all:promises];
        } else if (promises) {
            return [self all:@[promises]].then(^(NSArray *values){
                return [values objectAtIndex:0];
            });
        } else {
            return [PMKPromise promiseWithValue:nil];
        }
    }
    
    + (PMKPromise *)all:(id<NSFastEnumeration, NSObject>)promises {
        __block NSUInteger count = [(id)promises count];  // FIXME
        
        if (count == 0)
            return [PMKPromise promiseWithValue:promises];
    
        // Keep a reference to the newly created
        // promise so we can check if it's resolved
        // when one of the passed in promises fails.
        __block PMKPromise *newPromise = nil;
    
        #define rejecter(key) ^(NSError *err){ \
            if (newPromise.resolved) \
                return; \
            NSMutableDictionary *userInfo = err.userInfo.mutableCopy; \
            [userInfo setObject:key forKey:PMKFailingPromiseIndexKey]; \
            err = [NSError errorWithDomain:err.domain code:err.code userInfo:userInfo]; \
            rejecter(err); \
        }
    
        if ([promises isKindOfClass:[NSDictionary class]])
            return newPromise = [PMKPromise new:^(PMKPromiseFulfiller fulfiller, PMKPromiseRejecter rejecter){
                NSDictionary *promiseDictionary = (NSDictionary *) promises;
                NSMutableDictionary *results = [NSMutableDictionary new];
                for (id key in promiseDictionary) {
                    PMKPromise *promise = [promiseDictionary objectForKey:key];
                    if (![promise isKindOfClass:[PMKPromise class]])
                        promise = [PMKPromise promiseWithValue:promise];
                    promise.catch(rejecter(key));
                    promise.then(^(id o){
                        if (o)
                            [results setObject:o forKey:key];
                        if (--count == 0)
                            fulfiller(results);
                    });
                }
            }];
    
        return newPromise = [PMKPromise new:^(PMKPromiseFulfiller fulfiller, PMKPromiseRejecter rejecter){
            NSPointerArray *results = nil;
          #if TARGET_OS_IPHONE
            results = [NSPointerArray strongObjectsPointerArray];
          #else
            if ([[NSPointerArray class] respondsToSelector:@selector(strongObjectsPointerArray)]) {
                results = [NSPointerArray strongObjectsPointerArray];
            } else {
              #pragma clang diagnostic push
              #pragma clang diagnostic ignored "-Wdeprecated-declarations"
                results = [NSPointerArray pointerArrayWithStrongObjects];
              #pragma clang diagnostic pop
            }
          #endif
            results.count = count;
    
            NSUInteger ii = 0;
    
            for (__strong PMKPromise *promise in promises) {
                if (![promise isKindOfClass:[PMKPromise class]])
                    promise = [PMKPromise promiseWithValue:promise];
                promise.catch(rejecter(@(ii)));
                promise.then(^(id o){
                    [results replacePointerAtIndex:ii withPointer:(__bridge void *)(o ?: [NSNull null])];
                    if (--count == 0)
                        fulfiller(results.allObjects);
                });
                ii++;
            }
        }];
    
        #undef rejecter
    }
    

    第一个函数很简单不做介绍,主要看第二个函数

    1 参数 是promises ,必须能枚举的集合吧。数组字典set都可以。
    2 要是集合数量是0 ,那么直接返回一个PMKPromise,这里也是无奈啊,这个值不知道穿啥好,就把自己传回去了

    1. 要是promises 是个NSDictionary ,我们创建一个PMKPromise 命名为newPromise。我们知道这个newPromise 有两个状态回调block,分别是fulfillerrejecter,通过这两个block能将结果传入newPromise 中,因此,这里我们就将在字典中的所有promise 都分别或者通过字典值生成的promise 分别持有fulfillerrejecter,只要有一个promise 结果是NSerror ,那么我们就结束newPromise,让其保存NSError结果。所有promise要是没有错误,当每一个promise 结束的时候,将所有promise共享的计数器减1 ,当计数器变为0 的时候,也就是最后一个promise完成的时候,我们再将newPromise 的fulfiller 调用,让其newPromise 结束。数组同理。

    说的不明确,看图就行了,关系图


    image.png

    这里还有个until 用法,我就写个简单代码体会下。

     array = [NSMutableArray array];
       PMKPromise * p =  [PMKPromise promiseWithAdapter:^(PMKAdapter adapter) {
            adapter(@"nihao",nil);
        }];
        [array addObject:p];
        p =  [PMKPromise promiseWithAdapter:^(PMKAdapter adapter) {
            NSError * error = [NSError errorWithDomain:PMKErrorDomain code:PMKInvalidUsageError userInfo:nil];;
            adapter(@"error",error);
        }];
        [array addObject:p];
        [array addObject:@"dd"];
        [PMKPromise until:^id{
            return array;
        } catch:^(NSError * error){
            NSDictionary * dic = [error userInfo];
            NSNumber * num =[dic objectForKey:PMKFailingPromiseIndexKey];
            [array removeObjectAtIndex:num.integerValue];
            NSLog(@"%@",[error description]);
        }].then(^(id result){
            NSLog(@"%@",result);
        });
    

    运行结果

    2018-08-21 16:21:45.645773+0800 OriginCodeAnalytical[98249:1362520] Error Domain=PMKErrorDomain Code=3 "(null)" UserInfo={PMKFailingPromiseIndexKey=1}
    2018-08-21 16:21:45.647217+0800 OriginCodeAnalytical[98249:1362520] (
        nihao,
        dd
    )
    

    相关文章

      网友评论

        本文标题:PromiseKit源码分析

        本文链接:https://www.haomeiwen.com/subject/fjqnrftx.html