Bill
Bill

Reputation: 45466

In Combine, how do I run a series of futures in sequence?

Is there a Combine operator that will run a series of futures in sequence, running each to completion before starting the next?

I can do this with the very messy:

f1
.flatMap { _ in 
  f2
}.flatMap { _ in 
  f3
}.flatMap { _ in 
  // ... 
}

but I'd prefer something like:

sequence(f1, f2, f3, ...)

In some frameworks, this would look like:

f1.then { f2 }.then { f3 }

Upvotes: 2

Views: 1842

Answers (1)

Daniel T.
Daniel T.

Reputation: 33978

The key is to wrap the Future in a Deferred so it won't execute until it's time:

let f1 = Deferred { Future<Int, Error> { result in

    }
}
let f2 = Deferred { Future<Int, Error> { result in

    }
}
let f3 = Deferred { Future<Int, Error> { result in

    }
}
let jobs = f1
    .append(f2)
    .append(f3)

cancellable = jobs.sink(receiveCompletion: { (completion) in
    print("all three jobs done or one errored.")
}, receiveValue: { value in
    print("value of job:", value)
})

In response to further questions in the comments:

You cannot rely on Deferred to defer closure execution until a subscriber comes in, because Deferred is a struct and would cause a new Future to be created every time there is a new subscriber.

That's precisely the point of deferred. To create a new Future every time there is a new subscriber and not before then. Another option would be to create the futures inside the appends.

let jobs = Future<Int, Error> { result in }
    .append(Future<Int, Error> { result in })
    .append(Future<Int, Error> { result in })

But then all three futures will execute their code at the same time. I'm assuming you don't want this.

Upvotes: 1

Related Questions