Skip to content

Instantly share code, notes, and snippets.

@CodeDrivenDevelopment
Created April 20, 2024 19:45
Show Gist options
  • Save CodeDrivenDevelopment/af2c214a2f19c945add4db6238046c87 to your computer and use it in GitHub Desktop.
Save CodeDrivenDevelopment/af2c214a2f19c945add4db6238046c87 to your computer and use it in GitHub Desktop.
Some demo js files for showing how window.fetch works. Used for a demo on https://codedrivendevelopment.com/
'use client';
import { useState } from 'react';
const baseUrl = 'https://pokeapi.co/api/v2/pokemon/ditto';
const apiUrlWithCacheBusting = () => `${baseUrl}?${Date.now()}`;
export default function FetchDemo() {
const [abortTimeout, setAbortTimeout] = useState(50);
const [messages, setMessages] = useState<string[][]>([]);
const [userCancelSignal, setUserCancelSignal] = useState<AbortController>();
const appendMessage = (newMessage: string[]) => {
setMessages((prev) => [...prev, newMessage]);
};
const logWrapper = async (name: string, fetchFn: () => Promise<Response>) => {
const logs: string[] = [];
try {
logs.push(`${name}: fetching`);
const fetchResponse = await fetchFn();
logs.push(`${name}: got fetchResponse, now awaiting .json()`);
} catch (error) {
logs.push(`${name}: error: "${error}"`);
} finally {
logs.push(`${name}: finished`);
appendMessage(logs);
}
};
async function fetchWithAutomaticTimeout() {
const newUserCancelController = new AbortController();
setUserCancelSignal(newUserCancelController);
const timeoutSignal = AbortSignal.timeout(abortTimeout);
const signal = AbortSignal.any([
timeoutSignal,
newUserCancelController.signal,
]);
signal.addEventListener('abort', () => {
appendMessage('Aborted');
});
logWrapper('Fetch with manual abort', () =>
window.fetch(apiUrlWithCacheBusting(), {
signal,
}),
);
}
return (
<div>
<h1>
Getting url {baseUrl}, abort timeout set to {abortTimeout}ms
</h1>
<div className="flex justify-around">
<button onClick={() => setAbortTimeout(50)}>50ms</button>
<button onClick={() => setAbortTimeout(500)}>500ms</button>
<button onClick={() => setAbortTimeout(5000)}>5000ms</button>
</div>
<button onClick={() => userCancelSignal?.abort()}>Manual abort!</button>
<button onClick={fetchWithAutomaticTimeout}>
Fetch with automatic timeout abort
</button>
<hr />
<code>
<pre>{JSON.stringify(messages, null, 2)}</pre>
</code>
</div>
);
}
'use client';
import { useState } from 'react';
const baseUrl = 'https://pokeapi.co/api/v2/pokemon/ditto';
const apiUrlWithCacheBusting = () => `${baseUrl}?${Date.now()}`;
export default function FetchDemo() {
const [abortTimeout, setAbortTimeout] = useState(50);
const [messages, setMessages] = useState<string[][]>([]);
const appendMessage = (newMessage: string[]) => {
setMessages((prev) => [...prev, newMessage]);
};
const logWrapper = async (name: string, fetchFn: () => Promise<Response>) => {
const logs: string[] = [];
try {
logs.push(`${name}: fetching`);
const fetchResponse = await fetchFn();
logs.push(`${name}: got fetchResponse, now awaiting .json()`);
} catch (error) {
console.error(error);
logs.push(`${name}: error: "${error}"`);
} finally {
logs.push(`${name}: finished`);
appendMessage(logs);
}
};
async function normalFetch() {
logWrapper('Normal fetch', () => window.fetch(apiUrlWithCacheBusting()));
}
async function fetchWithManualAbort() {
logWrapper('Fetch with manual abort', () => {
const controller = new AbortController();
setTimeout(
() => controller.abort(`custom timeout abort after ${abortTimeout}ms`),
abortTimeout,
);
return window.fetch(apiUrlWithCacheBusting(), {
signal: controller.signal,
});
});
}
async function fetchWithManualAbortWithoutValue() {
logWrapper('Fetch with manual abort (no value)', () => {
const controller = new AbortController();
setTimeout(() => controller.abort(), abortTimeout);
return window.fetch(apiUrlWithCacheBusting(), {
signal: controller.signal,
});
});
}
async function fetchWithAutomaticTimeout() {
logWrapper('Fetch with manual abort', () =>
window.fetch(apiUrlWithCacheBusting(), {
signal: AbortSignal.timeout(abortTimeout),
}),
);
}
return (
<div>
<h1>
Getting url {baseUrl}, abort timeout set to {abortTimeout}ms
</h1>
<div className="flex justify-around">
<button onClick={() => setAbortTimeout(50)}>50ms</button>
<button onClick={() => setAbortTimeout(500)}>500ms</button>
<button onClick={() => setAbortTimeout(5000)}>5000ms</button>
</div>
<button onClick={normalFetch}>Normal fetch</button>
<button onClick={fetchWithManualAbort}>Fetch with manual abort</button>
<button onClick={fetchWithManualAbortWithoutValue}>
Fetch with manual abort (no value)
</button>
<button onClick={fetchWithAutomaticTimeout}>
Fetch with automatic timeout abort
</button>
<hr />
<code>
<pre>{JSON.stringify(messages, null, 2)}</pre>
</code>
</div>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment