1. Read Network Information
The browser may expose estimated bandwidth, latency, connection type, and data-saving preference through navigator.connection.
function readNetworkInformation() {
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
if (!connection) {
return {
supported: false,
message: "Network Information API is not supported in this browser."
};
}
return {
supported: true,
downlink: connection.downlink ?? "unknown",
downlinkMax: connection.downlinkMax ?? "unknown",
effectiveType: connection.effectiveType ?? "unknown",
rtt: connection.rtt ?? "unknown",
saveData: connection.saveData ?? false,
type: connection.type ?? "unknown"
};
}
2. Use Bandwidth as a Hint, Not a Truth
A high downlink value does not guarantee a fast image load. Server pressure, packet loss, throttling, and competing downloads still affect the real experience.
function chooseImageQuality(downlink, saveData) {
if (saveData) {
return "low";
}
if (downlink >= 5) {
return "high";
}
return "low";
}
3. Listen for Connection Changes
When supported, the change event can update front-end behavior after the network condition changes.
function watchConnectionChanges(onChange) {
const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
if (!connection) {
onChange("Connection change events are not supported here.");
return;
}
connection.addEventListener("change", () => {
onChange("Network changed: " + connection.effectiveType + ", " + connection.downlink + " Mbps");
});
}
4. Measure Actual Resource Loading
For image-heavy feeds, measuring several resource loads is more useful than trusting one bandwidth estimate.
function measureResourceLoad(sizeKb, speedKbps, onProgress, onComplete) {
const totalBytes = sizeKb * 1024;
let loadedBytes = 0;
const bytesPerTick = speedKbps * 1024 / 10;
const startedAt = performance.now();
const timer = setInterval(() => {
loadedBytes = Math.min(totalBytes, loadedBytes + bytesPerTick);
onProgress({
loaded: loadedBytes,
total: totalBytes,
percent: Math.round(loadedBytes / totalBytes * 100)
});
if (loadedBytes === totalBytes) {
clearInterval(timer);
onComplete(Math.round(performance.now() - startedAt));
}
}, 100);
}
5. Give the User a Choice
When the network looks poor, a product can prioritize readable content and let the user request the original quality.
function applyUserQualityChoice(choice) {
const state = {
quality: choice,
label: choice === "original" ? "Original image requested" : "Compressed image shown first",
estimatedSize: choice === "original" ? "3.6 MB" : "420 KB"
};
return state;
}
Compressed
Show content quickly with a smaller file.
View Original
Load the sharper image when the user asks for it.
6. Estimate Upload Time
Upload flows can respond to slow connections by extending patience and giving the user a realistic duration message.
function estimateUpload(fileMb, uploadMbps) {
const seconds = Math.ceil(fileMb * 8 / uploadMbps);
const slow = seconds > 20;
return {
seconds,
timeoutSeconds: slow ? seconds + 30 : seconds + 10,
message: slow
? "Your current network is not very good. This may take a while."
: "Upload should finish soon."
};
}