Responses are treated as a stream, so they can only be read once. This is why you see responses being cloned, or constructed into new responses. Mainly because of memory efficiency.
In this specific example:
// Resolves the fetch() Promise that returns a Response
response = await fetch(request)
// Headers are immutable, meaning we can't alter it unless we construct a new Response
response = new Response(response.body, response)
response.headers.append('Cache-Tag', 'apple')
// The cache API will consume the response, so we clone it to avoid buffering
event.waitUntil(cache.put(request, response.clone()))
// Return the newly created Response that hasn't been consumed yet
return response
The following article explains it with a little more details: