JavaScript AJAX - Exercise 3
Retry only when the failure is likely temporary, and prefer idempotent requests so repeating them does not create unintended side effects. The response can then be parsed and used to update part of the page without a full navigation.
async function loadWithRetry(url) {
for (let attempt = 1; attempt <= 3; attempt += 1) {
try {
return await fetch(url);
} catch (error) {
if (attempt === 3) throw error;
}
}
}A retry limit prevents infinite loops, reduces server load, and lets the user see a real failure instead of waiting forever. The response can then be parsed and used to update part of the page without a full navigation.
const maxRetries = 3;
if (attempt === maxRetries) {
throw new Error('Request failed after several attempts');
}Cancel the earlier request or ignore its result when a newer request has already started, especially in search and autocomplete UIs. The response can then be parsed and used to update part of the page without a full navigation.
let lastRequestId = 0;
async function search(term) {
const requestId = ++lastRequestId;
const response = await fetch(`/search?q=${encodeURIComponent(term)}`);
const results = await response.json();
if (requestId === lastRequestId) renderResults(results);
}Optimistic UI updates the interface before the server confirms the change, then reverts or corrects it if the request fails. The response can then be parsed and used to update part of the page without a full navigation.
likeButton.disabled = true;
likesCount.textContent = Number(likesCount.textContent) + 1;
try {
await fetch('/api/likes', { method: 'POST' });
} catch (error) {
likesCount.textContent = Number(likesCount.textContent) - 1;
}Serialize the data with JSON.stringify() and send it with the appropriate Content-Type header. The response can then be parsed and used to update part of the page without a full navigation.
fetch('/api/comments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: 'Nice post!' })
});A 401 Unauthorized response usually means the request is missing valid authentication credentials or the existing credentials have expired. The response can then be parsed and used to update part of the page without a full navigation.
if (response.status === 401) {
redirectToLogin();
}A 429 Too Many Requests response tells the client it has hit a rate limit and should slow down or retry later. The response can then be parsed and used to update part of the page without a full navigation.
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
console.log('Retry after:', retryAfter);
}Keep data-fetching logic in one function and DOM updates in another so each piece is easier to test, reuse, and debug. The response can then be parsed and used to update part of the page without a full navigation.
async function getUsers() {
const response = await fetch('/api/users');
return response.json();
}
function renderUsers(users) {
console.log(users);
}Useful feedback tells the user what happened and what to do next, while also giving developers enough context to troubleshoot failures. The response can then be parsed and used to update part of the page without a full navigation.
catch (error) {
showError('Could not save your changes. Please try again.');
console.error('Saving profile failed:', error);
}Promise.all() starts multiple independent requests together and waits until every one of them has finished. The response can then be parsed and used to update part of the page without a full navigation.
const [userResponse, postsResponse] = await Promise.all([
fetch('/api/user'),
fetch('/api/posts')
]);