PromiseKit基本使用及源碼解析

     Promise處理一系列異步操做的應用框架,可以保證順序執行一系列異步操做,當出錯時能夠經過catch捕獲錯誤進行處理。Promise框架也是很好的詮釋了swift的面相協議編程以及函數式編程編程

兩種類型 1Promise,2Guarantee 其中Guarantee沒有實現 CatchMixin 協議,不能捕獲錯誤,他是不容許拋出錯誤,經常使用的就是第一種類型,便於錯誤處理。Promise是承諾執行,有可能不執行;而guarantee是保證,保證必定執行swift

基本使用形式:api

func threeRequest111() {
         firstly {
                request1(with: ["test1": "first"])
            }
            .then { (v) -> Promise<NSDictionary> in
                print("🍀", v)
                return self.request2(para: ["test2": "second"])
            }
            .then { (v) -> Promise<NSDictionary> in
                print("🍀🍀", v)
                return self.request3(para: ["test3": "third"])
            }
            .map({ (dic) -> [String:String]  in
                if let dic1 = dic as? [String:String]{
                    return dic1
                }else{
                    return [String:String]()
                }
            }).done({ (dic) in
                print(dic)
            })
            .catch { (error) in
                print(error.localizedDescription)
        
            }.finally {
                print("finaly")
        }
    }

func request1(with parameters: [String: String]) -> Promise<(NSDictionary)> {數組

        return Promise<NSDictionary>(resolver: { (resolver) inpromise

            Alamofire.request("https://httpbin.org/get", method: .get, parameters: parameters).validate().responseJSON() { (response) in閉包

                switch response.result {app

                case .success(let dict):框架

                    delay(time: 1, task: {異步

                        resolver.fulfill(dict as! NSDictionary)async

                    })

                case .failure(let error):

                    resolver.reject(error)                  

                }

            }

        })

    }

    func request2(para:[String:String]) -> Promise<NSDictionary> {

        return request1(with: para)

    }

    func request3(para:[String:String]) -> Promise<NSDictionary> {

        return request1(with: para)
    }

 

                                                          源碼解析

一 開始帶着問題去想研究下源碼

1.如何保證一系列block順序執行的呢

把外部傳入的thenBlock等保存起來了,保存到一個數組中,handlers.append(to),當本身的任務執行完去執行存在數組的任務

2.閉包中返回值promise 如何與 firstly函數中的promise聯繫起來的

rv.pipe(to: rp.box.seal)

二。Promise 主要函數

1.then函數

func then<U: Thenable>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> U) -> Promise<U.T> {
        let rp = Promise<U.T>(.pending)
        pipe {//向上一個promise中添加任務
            switch $0 {
            case .fulfilled(let value):
                on.async(flags: flags) {
                    do {
                        let rv = try body(value)
                        guard rv !== rp else { throw PMKError.returnedSelf }
                        rv.pipe(to: rp.box.seal)
                    } catch {
                        rp.box.seal(.rejected(error))
                    }
                }
            case .rejected(let error):
                rp.box.seal(.rejected(error))
            }
        }
        return rp
    }

then函數中將pipe閉包(包括了外部須要執行的閉包)添加進上一個promise.box.handers中:

handlers.append(to)

to就是then函數中的pipe閉包,而且添加的時候時用柵欄函數同步添加的,保證了任務的順序執行

barrier.sync(flags: .barrier) {//柵欄同步

當上一個promise中的閉包(外部耗時任務)執行完,resever調用fufill:

resolver.fulfill(T) -> box.seal(.fulfilled(value)) ->

override func seal(_ value: T) {
        var handlers: Handlers<T>!
        barrier.sync(flags: .barrier) {
            guard case .pending(let _handlers) = self.sealant else {
                return  // already fulfilled!
            }
            handlers = _handlers
            self.sealant = .resolved(value)
        }
        if let handlers = handlers {
            handlers.bodies.forEach{ $0(value) }
        }
    }
帶着結果值執行handlers.bodies裏邊的任務(也就是下一個then中的block)實際上就是上邊天加進去的pipe閉包:

  pipe {//向上一個promise中添加任務

            switch $0 {

            case .fulfilled(let value):

                on.async(flags: flags) {

                    do {

                        let rv = try body(value)

                        guard rv !== rp else { throw PMKError.returnedSelf }

                        rv.pipe(to: rp.box.seal)//執行rp.handlers.foreach這個任務添加到rv.handlers

                    } catch {

                        rp.box.seal(.rejected(error))

                    }

                }

            case .rejected(let error):

                rp.box.seal(.rejected(error))

            }

        }

這裏邊又個比較繞的東西就是switch $0 是Result<T>類型,而調用的地方handlers.bodies.forEach{ $0(value) },傳入的value是T類型,不匹配,繞了一圈看了一下,初始化resolve時T表示了ResultT,這樣就時匹配的沒錯

 

咱們知道then函數block中須要返回一個Promise:rv,而then函數中有建立了一個Promise:rp,傳入下一個then函數中,下面以相鄰的兩個then函數再簡化的理解一下then{rv1:Promise}.then{rv2:promise}

rv1的handler中存的是rp1.box.seal也就是是否要執行rv2所在的那個pipe

 

 

 

2.catch 錯誤捕獲函數,爲何promise連中不管哪一環節報錯,都能走到catch中去呢

catch定義在CatchMixin協議中,promise是實現了這個協議的,catch它有默認實現:

@discardableResult
    func `catch`(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, policy: CatchPolicy = conf.catchPolicy, _ body: @escaping(Error) -> Void) -> PMKFinalizer {
        let finalizer = PMKFinalizer()
        pipe {
            switch $0 {
            case .rejected(let error):
                guard policy == .allErrors || !error.isCancelled else {
                    fallthrough
                }
                on.async(flags: flags) {
                    body(error)
                    finalizer.pending.resolve(())
                }
            case .fulfilled:
                finalizer.pending.resolve(())
            }
        }
        return finalizer
    }

catch通常在promise鏈中的最後或者finally前邊,因此它的返回值是PMKFinalizer

經過pipe把pipe的內容添加到了上一個promise的handels中

當promise鏈中任何一環執行reject(error)時,執行下一個promise中的seal

rp.box.seal(.rejected(error))

順着promise鏈一直往下走,每個都是執行這個,直到catch,走catch中的代碼任務

3.firstly,瞭解了t很函數以後再看firstly就容易理解多了,它比then不一樣地一點是,它是先執行由於他前邊沒有promise,它一個函數而不是promise的方法,返回值和then同樣,是個promise

public func firstly<U: Thenable>(execute body: () throws -> U) -> Promise<U.T> {
    do {
        let rp = Promise<U.T>(.pending)
        try body().pipe(to: rp.box.seal)//執行body,建立Promise,返回後執行pipe(外部多是異步的耗時操做,因此會先執行pipe(to),return rp,接着是外部的.then函數等)
        return rp
    } catch {
        return Promise(error: error)
    }
}

4.when函數,主要是實現前邊幾個任務同時進行,等他們都執行完,精心後邊的順序執行任務。

基本使用方式:

//request1和request2,並行執行,都執行完再執行request3;參數是個promise數組,多個任務同時執行
        when(fulfilled: [request1(with: ["para1":"hello"]),request2(para: ["para2":"nihao"])])
        .then { (dic) -> Promise<NSDictionary> in
            self.request3(para: ["uhu":"nih"])
            }.catch { (error) in
                print(error.localizedDescription)
        }
        //promises數組中是結果不一樣類型的promise,最多支持5種不一樣類型的Promise
        when(fulfilled: request1(with: ["para1":"hello"]), request4())
            .then { (arg0) -> Promise<[String:String]> in
            let (dic, str) = arg0
            return Promise<[String:String]>(resolver: { (res) in
                res.fulfill([str : "\(dic)"])
            })
            }.catch { (error) in
                print(error.localizedDescription)
        }
查看其源碼,經過兩個Int值,表示已經執行完的任務數和總共的任務數
private func _when<U: Thenable>(_ thenables: [U]) -> Promise<Void> {
    var countdown = thenables.count
    guard countdown > 0 else {
        return .value(Void())
    }

    let rp = Promise<Void>(.pending)

#if PMKDisableProgress || os(Linux)
    var progress: (completedUnitCount: Int, totalUnitCount: Int) = (0, 0)
#else
    let progress = Progress(totalUnitCount: Int64(thenables.count))
    progress.isCancellable = false
    progress.isPausable = false
#endif

    let barrier = DispatchQueue(label: "org.promisekit.barrier.when", attributes: .concurrent)

    for promise in thenables {
        promise.pipe { result in
            barrier.sync(flags: .barrier) {
                switch result {
                case .rejected(let error):
                    //若是是pending(等待)狀態,將錯誤往下傳遞,這個判斷確保了幾個並行的任務
                    //只有第一個出錯的任務它錯誤往下傳遞,由於一旦出錯其餘的任何任務都再無心義
                    if rp.isPending {
                        progress.completedUnitCount = progress.totalUnitCount
                        rp.box.seal(.rejected(error))
                    }
                case .fulfilled:
                    //這個條件確保了,若是幾個並行的任務有一個已經出錯,後來正確完成的任務到這裏再也不往下傳遞
                    guard rp.isPending else { return }
                    progress.completedUnitCount += 1
                    countdown -= 1
                    if countdown == 0 {
                        rp.box.seal(.fulfilled(()))
                    }
                }
            }
        }
    }

    return rp
}

5.race函數,和when函數對比來看,race參數也是幾個promise,不一樣的是它只有其中一個返回成功就往下傳遞繼續promise鏈,不用等這幾個任務全執行完,每一個執行完了都往下走一遍promise鏈這種需求可能應用的少一點

private func _race<U: Thenable>(_ thenables: [U]) -> Promise<U.T> {

    let rp = Promise<U.T>(.pending)

    for thenable in thenables {

        thenable.pipe(to: rp.box.seal)

    }

    return rp

}

二.看一下Promise提供的其餘函數

Map 轉換函數,將結果進行轉換
public func map<U>(on: DispatchQueue? = default, flags: DispatchWorkItemFlags? = default, _ transform: @escaping (Self.T) throws -> U) -> PromiseKit.Promise<U>
done函數,done函數和then函數的區別就是是block返回值是void,只是順序執行,二不須要上一步的結果值是用done函數
func done(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) throws -> Void) -> Promise<Void> 
Get函數,他和done差很少,只是會自動的返回上部的結果值
 func get(on: DispatchQueue? = conf.Q.return, flags: DispatchWorkItemFlags? = nil, _ body: @escaping (T) throws -> Void) -> Promise<T>
tap函數,他會返回一個Result<T>,你能夠從這裏查看返回的值,而不會對整個鏈產生任何反作用
func tap(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(Result<T>) -> Void) -> Promise<T>
asVoid函數,它返回一個新的promise,與上一個promise連起來,而上一個promise的值被拋棄
func asVoid() -> Promise<Void>

還有一些當結果值是Sequence(也就是數組)時的函數,對數組的一些理,和數組的一些高階函數差很少
public extension Thenable where T: Sequence 
func mapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) throws -> U) -> Promise<[U]>

附帶1,框架還封裝了一個KVO實現KVOProxy,爲Guarantee打造的一個KVO,任何一個類均可以添加一個觀察者,當收到觀察屬性變化時窒執行guarantee的內容,guarantee是一個保證,必定會執行,因此KVO中,KVOProxy本身持有本身,retainCycle = self,不收到回掉不會釋放

extension NSObject {
    public func observe(_: PMKNamespacer, keyPath: String) -> Guarantee<Any?> {
        return Guarantee { KVOProxy(observee: self, keyPath: keyPath, resolve: $0) }
    }
}

private class KVOProxy: NSObject {
    var retainCycle: KVOProxy?
    let fulfill: (Any?) -> Void

    @discardableResult
    init(observee: NSObject, keyPath: String, resolve: @escaping (Any?) -> Void) {
        fulfill = resolve
        super.init()
        observee.addObserver(self, forKeyPath: keyPath, options: NSKeyValueObservingOptions.new, context: pointer)
        retainCycle = self
        //持有本身形成循環引用,不收到回掉不會釋放
    }

    fileprivate override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if let change = change, context == pointer {
            defer { retainCycle = nil }//延時執行,所在做用域內最後執行,收到回掉後才進行釋放
            fulfill(change[NSKeyValueChangeKey.newKey])
            if let object = object as? NSObject, let keyPath = keyPath {
                object.removeObserver(self, forKeyPath: keyPath)
            }
        }
    }

    private lazy var pointer: UnsafeMutableRawPointer = {
        return Unmanaged<KVOProxy>.passUnretained(self).toOpaque()
    }()
}

附帶2,框架對alamofire作了了一些extension,請求的返回值能夠直接是一個promise,進行鏈式操做

相關文章
相關標籤/搜索