I'm not sure if that would work for code completion. Aside from tracking
which value belongs to which frontend, and the associated bugs with
hooks you mentioned, how to you invalidate the results?
For instance, there is a request, it has been made a while ago, and the
context has changed (the buffer has changed, position has changed, etc).
The request has taken a long time but finally the response has arrived.
How do you reliably ignore it? Or, ideally, are able abort it (if it's a
one-time external process, perhaps killing the search process)?
If the result is some kind of "future" value, the handler code can
either change some variable in the lexical scope once its execution
reaches the point of "we don't need that computation anymore", or could
even call some generic method like future-abort.
How does the general refresh hook solve these problems?