By the end of this lesson, you will:
Weather data changes gradually - perfect for polling:
// Weather data - use polling (every 5-15 minutes)
const WEATHER_POLL_INTERVAL = 10 * 60 * 1000; // 10 minutes
// Stock prices - might need real-time WebSockets
// Chat messages - definitely need real-time
// News updates - polling works fine
class WeatherDashboard {
constructor() {
this.pollInterval = null;
this.isPolling = false;
this.currentLocation = null;
}
startAutoRefresh(intervalMinutes = 10) {
// Prevent multiple intervals
this.stopAutoRefresh();
const intervalMs = intervalMinutes * 60 * 1000;
this.isPolling = true;
this.pollInterval = setInterval(() => {
this.refreshWeatherData();
}, intervalMs);
console.log(`Auto-refresh started: every ${intervalMinutes} minutes`);
}
stopAutoRefresh() {
if (this.pollInterval) {
clearInterval(this.pollInterval);
this.pollInterval = null;
this.isPolling = false;
console.log('Auto-refresh stopped');
}
}
}
async refreshWeatherData() {
if (!this.currentLocation) return;
try {
// Show update indicator
this.showUpdateIndicator();
const weatherData = await this.fetchWeather(this.currentLocation);
this.updateDisplay(weatherData);
this.updateLastRefreshTime();
// Reset error count on success
this.errorCount = 0;
} catch (error) {
console.error('Auto-refresh failed:', error);
this.handleRefreshError(error);
} finally {
this.hideUpdateIndicator();
}
}
handleRefreshError(error) {
this.errorCount = (this.errorCount || 0) + 1;
// Implement exponential backoff
if (this.errorCount >= 3) {
this.stopAutoRefresh();
this.showErrorMessage('Auto-refresh disabled due to repeated errors');
}
}
showUpdateIndicator() {
const indicator = document.getElementById('update-indicator');
indicator.innerHTML = `
<div class="update-status">
<span class="spinner"></span>
Updating weather data...
</div>
`;
indicator.style.display = 'block';
}
updateLastRefreshTime() {
const timeElement = document.getElementById('last-updated');
const now = new Date();
timeElement.textContent = `Last updated: ${now.toLocaleTimeString()}`;
}
showRefreshSuccess() {
const indicator = document.getElementById('update-indicator');
indicator.innerHTML = `
<div class="update-success">
✓ Data refreshed successfully
</div>
`;
// Hide after 2 seconds
setTimeout(() => {
indicator.style.display = 'none';
}, 2000);
}
.update-status {
background: #e3f2fd;
color: #1976d2;
padding: 8px 16px;
border-radius: 4px;
display: flex;
align-items: center;
gap: 8px;
}
.spinner {
width: 16px;
height: 16px;
border: 2px solid #1976d2;
border-top: 2px solid transparent;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
createAutoRefreshControls() {
const controlsHTML = `
<div class="auto-refresh-controls">
<label>
<input type="checkbox" id="auto-refresh-toggle">
Auto-refresh weather data
</label>
<select id="refresh-interval">
<option value="5">Every 5 minutes</option>
<option value="10" selected>Every 10 minutes</option>
<option value="15">Every 15 minutes</option>
<option value="30">Every 30 minutes</option>
</select>
<button id="refresh-now">Refresh Now</button>
</div>
`;
document.getElementById('controls').innerHTML = controlsHTML;
this.attachControlListeners();
}
attachControlListeners() {
const toggle = document.getElementById('auto-refresh-toggle');
const interval = document.getElementById('refresh-interval');
const refreshBtn = document.getElementById('refresh-now');
toggle.addEventListener('change', (e) => {
if (e.target.checked) {
const minutes = parseInt(interval.value);
this.startAutoRefresh(minutes);
} else {
this.stopAutoRefresh();
}
});
interval.addEventListener('change', (e) => {
if (this.isPolling) {
this.startAutoRefresh(parseInt(e.target.value));
}
});
refreshBtn.addEventListener('click', () => {
this.refreshWeatherData();
});
}
class WeatherDashboard {
constructor() {
this.isRefreshing = false;
this.lastRefreshTime = 0;
this.minRefreshInterval = 30000; // 30 seconds minimum
}
async refreshWeatherData() {
// Prevent simultaneous requests
if (this.isRefreshing) {
console.log('Refresh already in progress, skipping...');
return;
}
// Respect minimum interval
const timeSinceLastRefresh = Date.now() - this.lastRefreshTime;
if (timeSinceLastRefresh < this.minRefreshInterval) {
console.log('Too soon since last refresh, waiting...');
return;
}
this.isRefreshing = true;
this.lastRefreshTime = Date.now();
try {
await this.fetchAndUpdateWeather();
} finally {
this.isRefreshing = false;
}
}
}
class AdaptivePolling {
constructor() {
this.baseInterval = 10 * 60 * 1000; // 10 minutes
this.currentInterval = this.baseInterval;
this.lastDataChange = Date.now();
}
calculateNextInterval(newData, oldData) {
const hasSignificantChange = this.detectSignificantChange(newData, oldData);
if (hasSignificantChange) {
// Data is changing - poll more frequently
this.currentInterval = Math.max(
this.baseInterval / 2,
5 * 60 * 1000 // Minimum 5 minutes
);
this.lastDataChange = Date.now();
} else {
// Data stable - slow down polling
const timeSinceChange = Date.now() - this.lastDataChange;
if (timeSinceChange > 30 * 60 * 1000) { // 30 minutes stable
this.currentInterval = Math.min(
this.baseInterval * 2,
30 * 60 * 1000 // Maximum 30 minutes
);
}
}
return this.currentInterval;
}
detectSignificantChange(newData, oldData) {
if (!oldData) return true;
const tempChange = Math.abs(newData.temperature - oldData.temperature);
const conditionChange = newData.condition !== oldData.condition;
return tempChange >= 2 || conditionChange;
}
}
// Detect if device is on battery
function isBatteryOptimizationNeeded() {
if ('getBattery' in navigator) {
return navigator.getBattery().then(battery => {
return !battery.charging && battery.level < 0.3;
});
}
return false;
}
// Adjust polling based on battery
async adjustPollingForBattery() {
const needsOptimization = await isBatteryOptimizationNeeded();
if (needsOptimization && this.isPolling) {
console.log('Low battery detected, reducing polling frequency');
this.startAutoRefresh(30); // Reduce to 30 minutes
}
}
// Starter code structure
class YourWeatherDashboard {
constructor() {
// Initialize polling properties
}
startAutoRefresh(intervalMinutes) {
// TODO: Implement auto-refresh start
}
stopAutoRefresh() {
// TODO: Implement auto-refresh stop
}
async refreshWeatherData() {
// TODO: Implement data refresh with indicators
}
createControls() {
// TODO: Create user controls for auto-refresh
}
}
Key concepts you've learned:
💡 Pro Tip: Weather data doesn't change rapidly, so 10-15 minute intervals are usually perfect. Shorter intervals waste resources, longer intervals make data feel stale.
In Concept 11, we'll explore Error Handling and Retry Logic - building robust systems that gracefully handle API failures, network issues, and rate limiting to ensure your dashboard remains reliable.