The promise approach is more elegant and efficient. Historically it has sometimes led to complications, though. Particularly tricky is bidirectional streaming.
subscribe(downstream :Downstream) -> (upstream :Upstream)
The problem here is that all messages sent to `upstream` will normally be held until `subscribe()` itself returns a capability which they can be sent to. So if `subscribe()` doesn't return until the downstream direction is done (or canceled), then the upstream doesn't work.
HOWEVER, if you're using the C++ implementation, a solution to this was introduced two or so years ago. You can use `context.setPipeline()` to connect the pipelined capabilities without actually completing the RPC.
So, assuming you can rely on `setPipeline()` being available, then I would lean towards the promise approach rather than the handle approach.