美文网首页
Swift Promise

Swift Promise

作者: 单抽律化娜 | 来源:发表于2019-12-26 13:51 被阅读0次
import UIKit

struct Callback {
    let onFulfilled: (Any) -> Void
    let onRejected: (Any) -> Void
    let queue: DispatchQueue
    
    func callFulfill(_ value: Any, completion: @escaping () -> Void = { }) {
        queue.async(execute: {
            self.onFulfilled(value)
            completion()
        })
    }
    
    func callReject(_ error: Any, completion: @escaping () -> Void = { }) {
        queue.async(execute: {
            self.onRejected(error)
            completion()
        })
    }
}

enum State: CustomStringConvertible {
    
    case pending(callbacks: [Callback])
    
    case fulfilled(value: Any)
    
    case rejected(error: Any)
    
    var isPending: Bool {
        if case .pending = self {
            return true
        } else {
            return false
        }
    }
    
    var isFulfilled: Bool {
        if case .fulfilled = self {
            return true
        } else {
            return false
        }
    }
    
    var isRejected: Bool {
        if case .rejected = self {
            return true
        } else {
            return false
        }
    }
    
    var value: Any? {
        if case let .fulfilled(value) = self {
            return value
        }
        return nil
    }
    
    var error: Any? {
        if case let .rejected(error) = self {
            return error
        }
        return nil
    }
    
    var description: String {
        switch self {
        case .fulfilled(let value):
            return "Fulfilled (\(value))"
        case .rejected(let error):
            return "Rejected (\(error))"
        case .pending:
            return "Pending"
        }
    }
}

public final class Promise {
    
    private var state: State
    
    private let lockQueue = DispatchQueue(label: "promise_lock_queue", qos: .userInitiated)
    
    public init() {
        state = .pending(callbacks: [])
    }
    
    public init(value: Any) {
        state = .fulfilled(value: value)
    }
    
    public init(error: Any) {
        state = .rejected(error: error)
    }
    
    public convenience init(queue: DispatchQueue = DispatchQueue.global(qos: .userInitiated), work: @escaping (_ fulfill: @escaping (Any) -> Void, _ reject: @escaping (Any) -> Void) throws -> Void) {
        self.init()
        queue.async(execute: {
            do {
                try work(self.fulfill, self.reject)
            } catch let error {
                self.reject(error)
            }
        })
    }
    
    @discardableResult
    public func then(on queue: DispatchQueue = .main, _ onFulfilled: @escaping (Any) throws -> Promise) -> Promise {
        return Promise(work: { fulfill, reject in
            self.addCallbacks(
                on: queue,
                onFulfilled: { value in
                    do {
                        try onFulfilled(value).then(on: queue, fulfill, reject)
                    } catch let error {
                        reject(error)
                    }
            },
                onRejected: reject
            )
        })
    }
    
    @discardableResult
    public func then(on queue: DispatchQueue = .main, _ onFulfilled: @escaping (Any) throws -> Any) -> Promise {
        return then(on: queue, { (value) -> Promise in
            do {
                return Promise(value: try onFulfilled(value))
            } catch let error {
                return Promise(error: error)
            }
        })
    }
    
    @discardableResult
    public func then(on queue: DispatchQueue = .main, _ onFulfilled: @escaping (Any) -> Void, _ onRejected: @escaping (Any) -> Void = { _ in }) -> Promise {
        addCallbacks(on: queue, onFulfilled: onFulfilled, onRejected: onRejected)
        return self
    }
    
    @discardableResult
    public func `catch`(on queue: DispatchQueue = .main, _ onRejected: @escaping (Any) -> Void) -> Promise {
        return then(on: queue, { _ in }, onRejected)
    }
    
    public func reject(_ error: Any) {
        updateState(.rejected(error: error))
    }
    
    public func fulfill(_ value: Any) {
        updateState(.fulfilled(value: value))
    }
    
    public var isPending: Bool {
        return !isFulfilled && !isRejected
    }
    
    public var isFulfilled: Bool {
        return value != nil
    }
    
    public var isRejected: Bool {
        return error != nil
    }
    
    public var value: Any? {
        return lockQueue.sync(execute: {
            return self.state.value
        })
    }
    
    public var error: Any? {
        return lockQueue.sync(execute: {
            return self.state.error
        })
    }
    
    private func updateState(_ newState: State) {
        lockQueue.async(execute: {
            guard case .pending(let callbacks) = self.state else { return }
            self.state = newState
            self.fireIfCompleted(callbacks: callbacks)
        })
    }
    
    private func addCallbacks(on queue: DispatchQueue = .main, onFulfilled: @escaping (Any) -> Void, onRejected: @escaping (Any) -> Void) {
        let callback = Callback(onFulfilled: onFulfilled, onRejected: onRejected, queue: queue)
        lockQueue.async(flags: .barrier, execute: {
            switch self.state {
            case .pending(let callbacks):
                self.state = .pending(callbacks: callbacks + [callback])
            case .fulfilled(let value):
                callback.callFulfill(value)
            case .rejected(let error):
                callback.callReject(error)
            }
        })
    }
    
    private func fireIfCompleted(callbacks: [Callback]) {
        guard !callbacks.isEmpty else {
            return
        }
        lockQueue.async(execute: {
            switch self.state {
            case .pending:
                break
            case let .fulfilled(value):
                var mutableCallbacks = callbacks
                let firstCallback = mutableCallbacks.removeFirst()
                firstCallback.callFulfill(value, completion: {
                    self.fireIfCompleted(callbacks: mutableCallbacks)
                })
            case let .rejected(error):
                var mutableCallbacks = callbacks
                let firstCallback = mutableCallbacks.removeFirst()
                firstCallback.callReject(error, completion: {
                    self.fireIfCompleted(callbacks: mutableCallbacks)
                })
            }
        })
    }
    
    public static func all(_ promises: [Promise]) -> Promise {
        return Promise(work: { fulfill, reject in
            guard !promises.isEmpty else { fulfill([]); return }
            for promise in promises {
                promise.then({ value in
                    if !promises.contains(where: { $0.isRejected || $0.isPending }) {
                         fulfill(promises.flatMap { $0.value.map { [$0] } ?? [] })
                    }
                }, {_ in }).catch({ error in
                    reject(error)
                })
            }
        })
    }
    
    public static func race(_ promises: [Promise]) -> Promise {
        return Promise(work: { fulfill, reject in
            guard !promises.isEmpty else { fatalError() }
            for promise in promises {
                promise.then(fulfill, reject)
            }
        })
    }
}

相关文章

网友评论

      本文标题:Swift Promise

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