Skip to content

Make delay cancelable #26

@julasamer

Description

@julasamer

The delay method is currently not cancelable. I.e., if a requestCancel happens during the delay, the promise resolves successfully anyway:

var promise: Promise<(), NoError>?
func test() {
    promise = Promise(fulfilled: ()).delay(1).always { print("result: \($0)") }
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { self.promise?.requestCancel() }
}

Expected outcome: Promise is resolved after 0.5s with a cancelled result. Actual result: Promise is fulfilled with () after the delay, cancel is ignored.

I implemented another version in an extension that seems to do the job. The fact that the timer isn't actually cancelled is a little ugly though.

public func cancelableDelay(on context: PromiseContext? = nil, _ duration: TimeInterval) -> Promise {
    return self.then {
        result in
        Promise<Value, Error>(on: context ?? .default, {
            resolver in
            var cancelRequested = false
            resolver.onRequestCancel(on: .immediate) {
                _ in
                cancelRequested = true
                resolver.cancel()
            }
            
            _ = Promise<(), NoError>(fulfilled: ()).delay(duration).then(on: context ?? .default) {
                _ in
                guard !cancelRequested else { return }
                resolver.fulfill(with: result)
            }
        })
    }
}

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions