Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cancelation Story #5

Closed
aaronbrethorst opened this issue Jan 29, 2018 · 6 comments
Closed

Cancelation Story #5

aaronbrethorst opened this issue Jan 29, 2018 · 6 comments

Comments

@aaronbrethorst
Copy link

How does cancelation work for network requests, e.g.?

@shoumikhin
Copy link
Contributor

shoumikhin commented Jan 29, 2018

In general case, you'd need some sort of a custom cancellation token at this point, depending on what you plan to accomplish. For network requests specifically, you may find URLSessionTask APIs pretty handy, and use them like:

class Fetcher {
  var task: URLSessionDataTask?

  func fetch(url: URL) -> Promise<(Data?, URLResponse?)> {
    cancel()
    return wrap { (handler: @escaping (Data?, URLResponse?, Error?) -> Void) in
      self.task = URLSession.shared.dataTask(with: url, completionHandler: handler)
      self.task?.resume()
    }
  }

  func cancel() {
    task?.cancel()
  }
}

let fetcher = Fetcher()
fetcher.fetch(url: URL(string: "https://google.com")!).then { _, response in
  print(response)
}.catch { error in
  print(error)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
  fetcher.cancel()
}

@aaronbrethorst
Copy link
Author

Thanks for the example. I'd love to see this folded into your docs.

@shmidt
Copy link

shmidt commented Apr 25, 2018

@shoumikhin This will only cancel previous request if you make a new one, right?
So there is no way currently to just cancel promise?

@shoumikhin
Copy link
Contributor

shoumikhin commented Apr 26, 2018

@shmidt Some examples on how you'd like to cancel the promise are highly appreciated.

Keep in mind, one can always invoke promise.reject(error) anytime to trigger the failure scenario, if needed.

BTW, just noticed the above code can be simplified with wrap like so:

func fetch(url: URL) -> Promise<(Data?, URLResponse?)> {
  cancel()
  return wrap { (handler: @escaping (Data?, URLResponse?, Error?) -> Void) in
    self.task = URLSession.shared.dataTask(with: url, completionHandler: handler)
    self.task?.resume()
  }
}

@shmidt
Copy link

shmidt commented Apr 26, 2018

@shoumikhin Thanks for the fast reply.
In my case, I plan to run asynchronously time consuming NSTask process, which I would like to stop if user decides to close a window, so I was looking for some code similar to the one I found for ReactiveKit:

func getUser() -> Signal<User, ClientError> {
  return Signal { observer in
    let task = getUser(completion: { result in
      switch result {
      case .success(let user):
        observer.next(user)
        observer.completed()
      case .failure(let error):
        observer.failed(error)
    })

    return BlockDisposable {
      task.cancel()
    }
  }
} 

where task.cancel() will be called when signal gets disposed.

@ghost
Copy link

ghost commented Jul 31, 2018

current code:

    public static func download(token: Cancellation.Token? = nil) -> Promise<Data> {
        return Promise { fulfill, reject in
            // simulate download ..., typically data will come in chunks and will be cached ...  
            DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
                if let token = token, token.isCancellationRequested {
                    return reject(Error.cancel)
                } else {
                    return fulfill(Data())
                }
            })
        }
    }
    let source = Cancellation.Source()
    
    let promise = download(token: source.token)
        .then({ (data) in
            print("data -----> ", data)
        })
        .catch({ (error) in
            print("ERROR -> ", error)
        })
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
        // simulate user pressed stop downloading ...
        source.cancel()
    })

proposal:

implement something like this: https://github.com/vadymmarkov/When#fail
or maybe reevaluate #31

Other suggestions ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants