OCPromise-進階用法

OCPromise-用OC實現JS的Promise
上篇文章介紹了OCPromise的基本用法,這篇裏我將介紹幾個擴展方法。git

deliverOnMainThread

上篇結尾處提到過,OCPromise的任務都是在子線程上執行的,那麼咱們在接收任務結果時,若是須要進行UI的操做時,還須要本身手動切到主線程上,所以我提供了一個將任務結果傳遞到主線程的回調方法:github

OCPromise *p = Promise(^(resolve  _Nonnull resolve, reject  _Nonnull reject) {
        NSLog(@"start new Promise...");
        resolve(@123);
    });
    
    OCPromise *multiply = function(^OCPromise * _Nullable(id  _Nonnull value) {
        return Promise(^(resolve  _Nonnull resolve, reject  _Nonnull reject) {
            NSLog(@"calculating %ld x %ld ...", [value longValue], [value longValue]);
            resolve([NSNumber numberWithLong:[value longValue] * [value longValue]]);
        });
    });
    
    OCPromise *add = function(^OCPromise * _Nullable(id  _Nonnull value) {
        return Promise(^(resolve  _Nonnull resolve, reject  _Nonnull reject) {
            NSLog(@"calculating %ld + %ld ...", [value longValue], [value longValue]);
            resolve([NSNumber numberWithLong:[value longValue] + [value longValue]]);
        });
    });
    
    p.then(multiply).deliverOnMainThread(^(id  _Nonnull value) {
        NSLog(@"1 got value %@ on %@", value, [NSThread currentThread]);
    }).then(function(^OCPromise * _Nullable(id  _Nonnull value) {
        NSLog(@"2 got value %@ on %@", value, [NSThread currentThread]);
        return Promise(^(resolve  _Nonnull resolve, reject  _Nonnull reject) {
            resolve(@([value longValue] * 10));
        });
    })).then(add).deliverOnMainThread(^(id  _Nonnull value) {
        NSLog(@"3 got value %@ on %@", value, [NSThread currentThread]);
    }).then(function(^OCPromise * _Nullable(id  _Nonnull value) {
        NSLog(@"4 got value %@ on %@", value, [NSThread currentThread]);
        return nil;
    }));
2020-06-11 16:10:37.224503+0800 OCPromise_Example[56255:2885996] start new Promise...
2020-06-11 16:10:37.224690+0800 OCPromise_Example[56255:2885996] calculating 123 x 123 ...
2020-06-11 16:10:37.224909+0800 OCPromise_Example[56255:2885925] 1 got value 15129 on <NSThread: 0x6000022c85c0>{number = 1, name = main}
2020-06-11 16:10:37.224920+0800 OCPromise_Example[56255:2885996] 2 got value 15129 on <NSThread: 0x60000228a300>{number = 6, name = (null)}
2020-06-11 16:10:37.225055+0800 OCPromise_Example[56255:2885996] calculating 151290 + 151290 ...
2020-06-11 16:10:37.225182+0800 OCPromise_Example[56255:2885996] 4 got value 302580 on <NSThread: 0x60000228a300>{number = 6, name = (null)}
2020-06-11 16:10:37.225188+0800 OCPromise_Example[56255:2885925] 3 got value 302580 on <NSThread: 0x6000022c85c0>{number = 1, name = main}

經過打印結果咱們能夠看到一、3都是在主線程執行的,而且主線程的接收並不影響子線程任務結果在任務鏈中的傳遞。deliverOnMainThread的實際調用邏輯就是在子線程接收到上一個任務的結果,而後爲主線程添加一個異步任務來執行外部回調將結果傳出去,並在當前線程繼續將任務結果傳遞給下一個任務。segmentfault

map

map的做用就是改變上一個任務的結果並傳遞給下一個任務。這裏提供了兩種map方法,一種是實例方法:數組

p.then(multiply).map(^id _Nullable(id  _Nonnull value) {
        NSLog(@"got value before map %@", value);
        return @([value longValue] * 10);
    }).then(function(^OCPromise * _Nullable(id  _Nonnull value) {
        NSLog(@"got value after map %@", value);
        return nil;
    }));
2020-06-11 16:20:59.395731+0800 OCPromise_Example[56282:2892198] start new Promise...
2020-06-11 16:20:59.396130+0800 OCPromise_Example[56282:2892198] calculating 123 x 123 ...
2020-06-11 16:20:59.396406+0800 OCPromise_Example[56282:2892198] got value before map 15129
2020-06-11 16:20:59.396642+0800 OCPromise_Example[56282:2892198] got value after map 151290

這種map方式很好理解,接收到上一個任務的結果以後,執行回調,在回調內針對結果進行處理以後在return回去。這樣下一個任務接收到的入參就是已經處理過的值了。promise

另一種是靜態方法:網絡

OCPromise *map = OCPromise.map(@[p, add, multiply], ^id _Nullable(id  _Nonnull value) {
        return @([value longValue] * 10);
    });
    
    p.then(map).then(function(^OCPromise * _Nullable(id  _Nonnull value) {
        NSLog(@"got value %@", value);
        return nil;
    }));
2020-06-11 16:25:46.242822+0800 OCPromise_Example[56319:2895774] start new Promise...
2020-06-11 16:25:46.243068+0800 OCPromise_Example[56319:2895772] start new Promise...
2020-06-11 16:25:46.243111+0800 OCPromise_Example[56319:2895773] calculating 123 + 123 ...
2020-06-11 16:25:46.243134+0800 OCPromise_Example[56319:2895770] calculating 123 x 123 ...
2020-06-11 16:25:46.243378+0800 OCPromise_Example[56319:2895774] got value (
1230,
2460,
151290

)異步

有沒有發現和OCPromise.all很像?沒錯,OCPromise.map就是OCPromise.all和實例方法map的結合,OCPromise.map會用傳進來的任務數組生成一個all promise的對象,而數組內的每一個任務的執行結果都會再調用傳入的mapBlock得到一個新的值並最終存到結果數組中。函數

retry

retry顧名思義,就是在任務執行失敗(reject)後進行重試。咱們先看下函數定義:學習

OCPromise * retry(OCPromise *ocPromise, uint8_t times, int64_t delay/*ms*/);

入參一共有三個,第一個是須要執行的任務,第二個是重試的次數,第三個是每次重試的間隔時間(注意是毫秒值),返回值是一個OCPromise對象。
函數的定義很好理解,咱們只須要用retry函數建立一個OCPromise對象並對這個對象的執行結果進行監聽就行了。
應用場景常見的就是網絡請求的重試,下面我用一個模擬的網絡請求來舉例說明一下retry的用法:ui

- (void)startRequest {
    NSDictionary *params = @{@"page":@(self.page)};
    retry(OCPromise.resolve(params).then(self.requestPageData), 3, 200).then(function(^OCPromise * _Nullable(id  _Nonnull value) {
        NSLog(@"%@", value);
        return nil;
    })).catch(^(id  _Nonnull value) {
        NSLog(@"%@", value);
    });
}

- (OCPromise *)requestPageData {
    return function(^OCPromise * _Nullable(id  _Nonnull value) {
        return Promise(^(resolve  _Nonnull resolve, reject  _Nonnull reject) {
            [self requestDataWithParams:value completion:^(id data, NSError *error) {
                if (error) {
                    reject(error);
                } else {
                    resolve(data);
                }
            }];
        });
    });
}

- (void)requestDataWithParams:(NSDictionary *)params completion:(void (^) (id data, NSError *error))completion {
    NSLog(@"start request");
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //completion([NSString stringWithFormat:@"response data with request params %@", params], nil);
        completion(nil, [NSError errorWithDomain:(@"com.ocpromise.response.err") code:30001 userInfo:@{@"description":@"error"}]);
    });
}
2020-06-11 16:46:55.107129+0800 OCPromise_Example[56431:2909131] start request
2020-06-11 16:46:56.323393+0800 OCPromise_Example[56431:2909131] start request
2020-06-11 16:46:57.624308+0800 OCPromise_Example[56431:2909130] start request
2020-06-11 16:46:58.674446+0800 OCPromise_Example[56431:2909032] Error Domain=com.ocpromise.response.err Code=30001 "(null)" UserInfo={description=error}

咱們用requestDataWithParams函數模擬了一個網絡請求,內部用一個延時函數模擬請求的延時,而且返回一個請求失敗的結果。而後咱們將這個網絡請求包裝成一個OCPromise對象requestPageData,當執行startRequest方法時,咱們生成了針對requestPageData的retry函數,並對結果進行監聽,當咱們的請求失敗了三次以後catch到了最終結果。

以上就是基於OCPromise的基本方法有擴展的一些使用方法。

你們若是感興趣能夠下載這個庫,幫忙給找找bug,提提意見,幫助我學習些新的思路或者擴展一下應用場景。感謝!

github:OCPromise

相關文章
相關標籤/搜索