125 lines
2.9 KiB
Markdown
125 lines
2.9 KiB
Markdown
# Performance, Best Practices & Accessibility
|
|
|
|
## Performance Optimization
|
|
|
|
### Debounced Search
|
|
|
|
```javascript
|
|
function debounce(func, wait) {
|
|
let timeout;
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
clearTimeout(timeout);
|
|
func(...args);
|
|
};
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
};
|
|
}
|
|
|
|
const debouncedFilter = debounce(filterStores, 300);
|
|
|
|
document.getElementById('search-input').addEventListener('input', (e) => {
|
|
debouncedFilter(e.target.value);
|
|
});
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### Data Management
|
|
|
|
```javascript
|
|
// GOOD: Load data once, filter in memory
|
|
const allStores = await fetch('/api/stores').then((r) => r.json());
|
|
|
|
function filterStores(criteria) {
|
|
return {
|
|
type: 'FeatureCollection',
|
|
features: allStores.features.filter(criteria)
|
|
};
|
|
}
|
|
|
|
// BAD: Fetch on every filter
|
|
async function filterStores(criteria) {
|
|
return await fetch(`/api/stores?filter=${criteria}`).then((r) => r.json());
|
|
}
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
```javascript
|
|
// Geolocation error handling
|
|
navigator.geolocation.getCurrentPosition(
|
|
successCallback,
|
|
(error) => {
|
|
let message = 'Unable to get your location.';
|
|
|
|
switch (error.code) {
|
|
case error.PERMISSION_DENIED:
|
|
message = 'Please enable location access to see nearby stores.';
|
|
break;
|
|
case error.POSITION_UNAVAILABLE:
|
|
message = 'Location information is unavailable.';
|
|
break;
|
|
case error.TIMEOUT:
|
|
message = 'Location request timed out.';
|
|
break;
|
|
}
|
|
|
|
showNotification(message);
|
|
},
|
|
{
|
|
enableHighAccuracy: true,
|
|
timeout: 5000,
|
|
maximumAge: 0
|
|
}
|
|
);
|
|
|
|
// API error handling
|
|
async function loadStores() {
|
|
try {
|
|
const response = await fetch('/api/stores');
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
}
|
|
|
|
const data = await response.json();
|
|
return data;
|
|
} catch (error) {
|
|
console.error('Failed to load stores:', error);
|
|
showNotification('Unable to load store locations. Please try again.');
|
|
return { type: 'FeatureCollection', features: [] };
|
|
}
|
|
}
|
|
```
|
|
|
|
## Accessibility
|
|
|
|
```javascript
|
|
// Add ARIA labels
|
|
document.getElementById('search-input').setAttribute('aria-label', 'Search stores');
|
|
|
|
// Keyboard navigation
|
|
document.querySelectorAll('.listing').forEach((listing, index) => {
|
|
listing.setAttribute('tabindex', '0');
|
|
listing.setAttribute('role', 'button');
|
|
listing.setAttribute('aria-label', `View ${listing.querySelector('.title').textContent}`);
|
|
|
|
listing.addEventListener('keypress', (e) => {
|
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
e.preventDefault();
|
|
listing.click();
|
|
}
|
|
});
|
|
});
|
|
|
|
// Focus management
|
|
function highlightListing(id) {
|
|
const listing = document.getElementById(`listing-${id}`);
|
|
listing.classList.add('active');
|
|
listing.focus();
|
|
listing.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
}
|
|
```
|