Created
April 20, 2024 19:45
-
-
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/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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