How to make use of the render placeholder system for cacheablejsonresponse?
The only trade-off I have found is to implement custom tags (per user) and put the response data array in cache so I have control over the conditions of cacheability at the controller level. I build the cacheability metadata (context + tags) with the help of a service which registers the metadata of the content which is currently normalized. And when the normalization ends, I merge the metadata onto the response and put the response in a cache backend.

And when the controller is called again, I try to retrieve the cached response and returns it if not invalidated.

Internal and dynamic page cache still works for the other controllers (i.e. standard rendered pages) without removing the high invalidation tags from the services.yml file.

Feel free to add better answers than this one.

Tested on Drupal 8.6.7.

Side note

Because I was using flag, I have had to implement cache tags pairs: userid+flaggingid. This way, we will not invalidate the caches of all users whenever a single user flags or unflags a content. This does not answer this question, but I thought it could be useful to include in your reflections for your own cache system.