Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't return a promise chain with a catch block on the end

This used to work but with version 6 of PromiseKit this...

func checkIn(request: CheckinRequest) -> Promise<CheckinResponse> {

        let p = checkinService.checkIn(request: request)

            .then { r -> Promise<CheckinResponse> in

                return .value(r)

            }.catch { e in


            }

        return p
    }

... gives ...

Cannot convert return expression of type 'PMKFinalizer' to return type 'Promise'

How can I add a catch block and continue to return the chain to the calling function?

like image 473
Ian Warburton Avatar asked Dec 13 '18 21:12

Ian Warburton


People also ask

Can I return a Promise from a catch?

The Promise returned by catch() is rejected if onRejected throws an error or returns a Promise which is itself rejected; otherwise, it is fulfilled.

When chaining promises together what is returned with the reject method?

In the above program, a Promise object is created that takes two functions: resolve() and reject() . resolve() is used if the process is successful and reject() is used when an error occurs in the promise. The promise is resolved if the value of count is true.

What promises reject returns?

The Promise. reject() method returns a Promise object that is rejected with a given reason.


2 Answers

You just need to remove the catch block as below,

func checkIn(request: CheckinRequest) -> Promise<CheckinResponse> {
     let p = checkinService.checkIn(request: request)
          .then { r -> Promise<CheckinResponse> in
              return .value(r)
        }
      return p
}

Using the catching block here is irrelevant as the error should be handled by the callee.


Guarantee class is a wrapper class to make discardable result calls. So we can create a method that will process the promise so that we will just use the .done callback to use that result as below,

extension Promise {

    func result() -> Guarantee<T> {
        return Guarantee<T>(resolver: { [weak self] (body) in
            self?.done({ (result) in
                body(result)
            }).catch({ (error) in
                print(error)
            })
        })
    }
}

Now you can simply do,

let request = CheckinRequest()
checkinService.checkIn(request: request).result().done { response in
    // Check in response
}

You can still use chaining for multiple promises as below,

checkinService.checkIn(request: request).result().then { (result) -> Promise<Bool> in
        // Use reuslt
        return .value(true)
    }.done { bool in
        print(bool)
    }.catch { (e) in
        print(e)
}
like image 137
Kamran Avatar answered Oct 22 '22 13:10

Kamran


Everything you need to know is described here, just scroll to the .catch{ /*…*/ }.finally section.

You can use this solution if you want to keep the same functionality:

func checkIn(request: CheckinRequest) -> Promise<CheckinResponse> {
    let p = checkinService.checkIn(request: request).then { r -> Promise<CheckinResponse> in
        return .value(r)
    }
    p.catch { e in

    }
    return p
}

However, it is not recommended to use this pattern. catch is a chain terminator. Therefore, you should refactor your code. Check Kamran's answer for inspiration.

like image 2
Roman Podymov Avatar answered Oct 22 '22 13:10

Roman Podymov