Q:

Caching queries not working as expected

I think I am not fully understanding how caching works. 
Based on this answer I thought I could cache my query and then shuffle the resulting array items.  
So I ended up with this code:
{% cache %}
  {% set categoryProducts = craft.entries.section('products').relatedTo(category) %}
{% endcache %}

{% set categoryProducts = shuffle(categoryProducts) %}
{% for entry in categoryProducts %}
  ...
{% endfor %}

But that does give me a "categoryProducts" does not exist error. 
Could someone shed some light as to why caching the query doesn't work?  I thought caching tags help to reduce the amount of queries being made and I've been studying the documentation, but I don't seem to fully grasp the concept. 

A:

The {% cache %} tag only caches the HTML output.   That's it. 
In your example above, nothing is cached, and categoryProducts will be an empty set. 
One thing you could do is to cache each entry individually:
{% set categoryProducts = craft.entries.section('products').relatedTo(category) %}
{% set categoryProducts = shuffle(categoryProducts) %}

{% for entry in categoryProducts %}
    {% cache globally using key 'product-' ~ entry.id %}
        ...
    {% endcache %}
{% endfor %}

