如何使用 PromiseKit 重构快速回调以承诺

Posted

技术标签:

【中文标题】如何使用 PromiseKit 重构快速回调以承诺【英文标题】:How to refactor swift callback to promise with PromiseKit 【发布时间】:2016-03-25 00:28:35 【问题描述】:

在使用 node.js 中的 bluebird 完成一些经验之后,我正在尝试第一次尝试使用 PromiseKit 进行快速承诺。我使用回调进行身份验证的原始服务函数如下所示:

private func requestNewToken(email : String, password: String,
completion: (success: Bool, token: String?, userId : String?, message: String? ) -> Void) 

Alamofire.request(Router.Authenticate(email, password).URLRequest)
    .responseJSON  request, response, result in
        switch result 
        case .Success(let data):
            let jsonData = JSON(data)

            let success = jsonData["success"].bool!
            let message = jsonData["message"].string!

            if(success) 
                let token = jsonData["token"].string
                let userId = jsonData["_id"].string

                self.deleteSavedUser()
                self.saveUserToCoreData(email, password: password, token: token!, userId: userId!)
                completion(success: true, token: token, userId: userId, message:  message)
                return
            

            completion(success: false, token: nil, userId: nil, message: message)
            print("Token request failed with error: \(message)")

        case .Failure(_, let error):
            print("Request failed with error: \(error)")
            completion(success: false, token: nil, userId : nil, message: nil)
        


我正在尝试重写为这样的内容:

private func requestNewTokenPromise(email : String, password:
String) -> Promise<UserLoginData?>         
 return Promise fulfill, reject in             
   Alamofire.request(Router.Authenticate(email,password).URLRequest)
        .responseJSON  request, response, result in
            switch result 
            case .Success(let data):
                let jsonData = JSON(data)
                fulfill(jsonData)
            case .Failure(_, let error):
                print("Request failed with error: \(error)")
                reject(error)
            
        
.then  json in

            let success = json["success"].bool!
            let message = json["message"].string!

            if(success) 
                let token = json["token"].string
                let userId = json["_id"].string

                self.deleteSavedUser()
                self.saveUserToCoreData(email, password: password, token: token!, userId: userId!) //sets the class's savedUser property

                return Promise(self.savedUser);
            

            return Promise(nil);            
   

但是,我的 then 行出现错误:

AuthenticationService.swift:147:6: Cannot convert return expression of type 'Promise<AnyObject?>' 
(aka 'Promise  Optional<AnyObject>> ') to return type 'Promise<UserLoginData?>' (aka 'Promise<Optional<UserLoginData>>')

我曾认为通过使用 Promise() 解决承诺,我将实现原始承诺类型。我哪里错了?

【问题讨论】:

【参考方案1】:

我假设代码可以直接发送到 Promise 是错误的,有时您只需要包装一个回调:

public func login(email: String, password: String) -> Promise<UserLoginData> 
        return Promise  fulfill, reject in
            requestNewToken(email, password: password)
                success, returnToken, userId, message in

                if(!success)
                    reject(LoginError.LoginFailed(message))
                    return
                
                self.deleteSavedUser()
                self.saveUserToCoreData(email, password: password, token: returnToken!, userId: userId!)
                let user = self.fetchUserFromCoreData()
                fulfill(user!)
            
        
    

【讨论】:

代码可以直接发送到 Promise,你只是缺少类型数据。 当您完全控制代码时,您是正确的。在这种特殊情况下,由于我使用的是 3rd 方库,因此我受限于它们提供的机制。回调是我使用 Alamofire 的唯一选择,所以最好将它包装起来,并将我的代码放在返回的 Promise 中。 PromiseKit 曾经在一年半前与 mxcl 谈论它时自动包装 alamofire。想知道这是否仍然有效。另外,请注意,我只是指出为什么您需要您的解决方案 - 我并没有说这是错误的。 我得研究一下 alamofire/promisekit 的事情,谢谢!

以上是关于如何使用 PromiseKit 重构快速回调以承诺的主要内容,如果未能解决你的问题,请参考以下文章

PromiseKit 3.0:用循环链接

PromiseKit 没有回调/解除分配? (阿拉莫菲尔)

PromiseKit - 带有重新加载第一个承诺的可选承诺

自己的 Promisekit 承诺没有正确响应

PromiseKit 如何将“when(resolved)”作为承诺返回?

返回使用另一个 PromiseKit 承诺的承诺