js实现文件上传限速
文件上传限速实现方法
在JavaScript中实现文件上传限速可以通过控制上传数据块的速率来实现。以下是几种常见的方法:
使用XMLHttpRequest和定时器
通过分块上传文件并控制每个数据块的上传间隔来实现限速:
function uploadWithThrottle(file, url, maxSpeed) {
const chunkSize = 1024 * 10; // 10KB
const totalChunks = Math.ceil(file.size / chunkSize);
let currentChunk = 0;
const delay = (chunkSize / maxSpeed) * 1000; // 毫秒
function uploadNextChunk() {
if (currentChunk >= totalChunks) return;
const start = currentChunk * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);
const xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.setRequestHeader('X-Chunk-Index', currentChunk);
xhr.setRequestHeader('X-Total-Chunks', totalChunks);
xhr.onload = function() {
currentChunk++;
setTimeout(uploadNextChunk, delay);
};
xhr.send(chunk);
}
uploadNextChunk();
}
使用Fetch API和AbortController
利用Fetch API和AbortController实现更精细的控制:
async function throttledUpload(file, url, maxSpeed) {
const chunkSize = 1024 * 10; // 10KB
const totalChunks = Math.ceil(file.size / chunkSize);
const controller = new AbortController();
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);
const startTime = Date.now();
try {
await fetch(url, {
method: 'POST',
body: chunk,
headers: {
'Content-Type': 'application/octet-stream',
'X-Chunk-Index': i,
'X-Total-Chunks': totalChunks
},
signal: controller.signal
});
const elapsed = Date.now() - startTime;
const expectedTime = (chunkSize / maxSpeed) * 1000;
if (elapsed < expectedTime) {
await new Promise(resolve =>
setTimeout(resolve, expectedTime - elapsed));
}
} catch (error) {
if (error.name !== 'AbortError') throw error;
}
}
}
使用Web Worker进行后台限速
将上传逻辑放在Web Worker中以避免阻塞主线程:
// worker.js
self.onmessage = function(e) {
const { file, url, maxSpeed } = e.data;
const chunkSize = 1024 * 10;
const totalChunks = Math.ceil(file.size / chunkSize);
(async function() {
for (let i = 0; i < totalChunks; i++) {
const start = i * chunkSize;
const end = Math.min(start + chunkSize, file.size);
const chunk = file.slice(start, end);
const startTime = Date.now();
try {
await fetch(url, {
method: 'POST',
body: chunk,
headers: {
'Content-Type': 'application/octet-stream',
'X-Chunk-Index': i,
'X-Total-Chunks': totalChunks
}
});
const elapsed = Date.now() - startTime;
const expectedTime = (chunkSize / maxSpeed) * 1000;
if (elapsed < expectedTime) {
await new Promise(resolve =>
setTimeout(resolve, expectedTime - elapsed));
}
self.postMessage({
progress: (i + 1) / totalChunks
});
} catch (error) {
self.postMessage({ error: error.message });
break;
}
}
})();
};
计算上传速度的辅助函数
实现一个计算实时上传速度的函数:
function calculateSpeed(startTime, endTime, bytesSent) {
const duration = (endTime - startTime) / 1000; // 转换为秒
const speed = bytesSent / duration; // 字节/秒
return {
bytesPerSecond: speed,
kilobytesPerSecond: speed / 1024,
megabitsPerSecond: (speed * 8) / (1024 * 1024)
};
}
注意事项
- 分块大小应根据实际需求调整,过小会增加请求次数,过大则限速效果不明显
- 服务器需要支持分块上传并能够重组文件
- 网络延迟会影响实际的上传速度,限速值应略低于目标值
- 对于大文件上传,应考虑加入暂停/恢复功能
- 浏览器兼容性问题需要考虑,特别是对于较旧的浏览器
以上方法可以根据具体需求进行组合和调整,以实现精确的文件上传限速控制。







