-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
In RxSwift, dispatching is an attribute of the chain. You switch dispatchers with a separate chain operator, e.g.
observable
.observeOn(MainScheduler.instance)
.subscribe { event in
...
}
...I believe ReactiveSwift works similarly, but I'm not as familiar with that library.
I love PromiseKit's simple convention of requiring an explicit dispatcher specification for each step in a chain unless you want to use the global default. It's direct and easily understood. I wouldn't want to change this system as the default.
Nevertheless, there's no reason why PromiseKit couldn't also, optionally, allow you to set a default dispatcher for a chain, and there are a couple of nice benefits that would come from this ability.
I'll mention some of the advantages below, but let me first clarify exactly what I'm talking about. Here's a straw-man proposal:
- Promises gain
setDefaultMapDispatcherandsetDefaultReturnDispatchermethods (terrible placeholder names...) with a signature something like
public func setDefaultMapDispatcher(_ on: Dispatcher? = nil) -> Promise<T>-
As usual, the returned promise is different from the original; it's a wrapper. Only subsequent chain elements added via the wrapper see the new default.
-
Any subsequent method uses the specified default dispatcher if nothing more specific is requested.
conf.Qstill exists but is consulted only if no chain-specific default has been set. -
Methods that return new promises silently propagate the default dispatcher to them.
Benefits
-
Clearer and more self-documenting than
conf.Q. I would hazard a guess that some users initially assume thatconf.Qis consulted at the point of actual dispatch. But in fact, it's consulted at chain construction time through the default argument mechanism. This is useful because it allows differentconf.Qvalues to be set for different regions of code, but it's not very discoverable without experimentation. -
Chains don't affect each other. By contrast, there's only one
conf.Q, and code has to take explicit precautions (save/restore) to avoid fighting over it. -
Code is cleaner without repeating
on:for every clause. -
Purely additive: nothing changes unless you use the feature.
-
Facilitates debugging because you can easily set a temporary default for any portion of a chain. It's one line added or removed which affects no other code. With
conf.Q, you have to add a variable assignment at the start of the chain, stop in the middle of the chain to setconf.Q, then resume the chain from the variable. -
The big one: it allows functions that yield or propagate promises to specify (suggest, really) dispatching policy. Result types that aren't thread-safe can return themselves with dispatching set to a serial queue. For example, a routine that returns a
Promise<NSManagedObject>might set the chain's default dispatcher to aCoreDataDispatcherfor the appropriateNSManagedObjectContextso that the managed object can be freely manipulated with no additional code on the receiver's end. E.g.,
fetchUser(managerID).map { manager in
(manager.firstName, manager.lastName)
}.done { name in
button.setTitle("Email \(name.0) \(name.1)", for: .normal)
}Thoughts?