Suppose you fetch a JSON document, call response.json(), and then try response.text() to inspect the original text. The second operation normally rejects. Both methods need to consume the same response body, and that body is a stream rather than a reusable copy of the downloaded document.
Reading does not have to finish before this matters. Once a non-null body stream is disturbed by reading or cancellation, it cannot be consumed again through the response. A body is also unusable while its stream is locked to a reader. Calling response.clone() on an unusable response throws a TypeError; body-consuming methods reject their promises when the body is unusable.
When two consumers genuinely need their own reads, clone first:
async function loadDocument() {
const response = await fetch('/document.json');
if (response.status !== 200) {
throw new Error(`HTTP ${response.status}`);
}
const copy = response.clone();
const [text, data] = await Promise.all([
response.text(),
copy.json()
]);
return { text, data };
}
This hypothetical endpoint is expected to return a small JSON document. The original and the clone each provide a body for one consumer. The caller still needs to handle network failures and invalid JSON. A successful HTTP status alone does not prove the document is valid JSON.
Cloning a response with a body tees its stream into two branches. It does not make a second request to the server. The branches can progress at different speeds, but that convenience has a cost: unread data can accumulate for the slower branch. If one branch is never consumed, the entire body may be buffered for it. Avoid this pattern for a large or unbounded response unless you have designed and tested the memory behavior.
Often the simpler answer is to read once and reuse the result. For a small document, const text = await response.text() followed by JSON.parse(text) gives you both the source string and parsed value without a cloned stream. Treat that string carefully if it contains secrets or personal information.
bodyUsed is useful, but it is not a complete availability test. A freshly acquired reader locks the body even before reading, so bodyUsed can still be false while cloning fails. Releasing that reader without reading can make the undisturbed body available again. Once it has been read or canceled, releasing the lock does not rewind it.
Finally, responses with a null body are a separate case. The ordinary one-pass warning concerns a present body stream, not an absent stream that has no bytes to consume.

The Campfire
CommentsThanks. Your comment is waiting for the desk. Once it is approved it appears here within about a minute.
Add a comment