文章目录
1. 分批上传(Batch Upload)
将大量图片分成小批次上传,而不是一次性全部上传:
async function batchUpload(files, batchSize = 5) {
for (let i = 0; i < files.length; i += batchSize) {
const batch = files.slice(i, i + batchSize);
await Promise.all(batch.map(file => uploadFile(file)));
}
}
2. 并发控制
限制同时上传的文件数量,避免浏览器连接数限制和服务器压力:
class UploadManager {
constructor(concurrency = 3) {
this.concurrency = concurrency;
this.running = 0;
this.queue = [];
}
async upload(file) {
return new Promise((resolve, reject) => {
this.queue.push({ file, resolve, reject });
this.process();
});
}
async process() {
if (this.running >= this.concurrency || this.queue.length === 0) {
return;
}
this.running++;
const { file, resolve, reject } = this.queue.shift();
try {
const result = await this.uploadFile(file);
resolve(result);
} catch (error) {
reject(error);
} finally {
this.running--;
this.process();
}
}
}
3. 图片压缩
在上传前对图片进行压缩,减小文件大小:
function compressImage(file, quality = 0.8) {
return new Promise((resolve) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
canvas.toBlob(resolve, 'image/jpeg', quality);
};
img.src = URL.createObjectURL(file);
});
}
4. 进度显示与状态管理
提供清晰的上传进度反馈:
function uploadWithProgress(file, onProgress) {
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (event) => {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
onProgress(percentComplete);
}
});
// 配置并发送请求
xhr.open('POST', '/upload');
const formData = new FormData();
formData.append('file', file);
xhr.send(formData);
}
5. 暂停/恢复功能
实现断点续传功能,支持暂停和恢复:
class ResumableUpload {
constructor(file) {
this.file = file;
this.chunkSize = 1024 * 1024; // 1MB chunks
this.chunks = Math.ceil(file.size / this.chunkSize);
this.uploadedChunks = new Set();
}
async uploadChunk(chunkIndex) {
const start = chunkIndex * this.chunkSize;
const end = Math.min(start + this.chunkSize, this.file.size);
const chunk = this.file.slice(start, end);
// 上传分片逻辑
await this.sendChunk(chunk, chunkIndex);
this.uploadedChunks.add(chunkIndex);
}
async resume() {
for (let i = 0; i < this.chunks; i++) {
if (!this.uploadedChunks.has(i)) {
await this.uploadChunk(i);
}
}
}
}
6. 预加载与预览
在上传前提供图片预览功能:
function previewImages(files) {
const previewContainer = document.getElementById('preview');
Array.from(files).forEach(file => {
if (!file.type.startsWith('image/')) return;
const reader = new FileReader();
reader.onload = (e) => {
const img = document.createElement('img');
img.src = e.target.result;
img.style.maxWidth = '200px';
img.style.maxHeight = '200px';
previewContainer.appendChild(img);
};
reader.readAsDataURL(file);
});
}
7. 错误处理与重试机制
实现错误处理和自动重试机制:
async function uploadWithRetry(file, maxRetries = 3) {
for (let i = 0; i <= maxRetries; i++) {
try {
return await uploadFile(file);
} catch (error) {
if (i === maxRetries) throw error;
// 指数退避策略
await new Promise(resolve => setTimeout(resolve, 2 ** i * 1000));
}
}
}
8. Web Workers优化
对于图片处理等计算密集型任务,使用Web Workers避免阻塞主线程:
// main.js
const worker = new Worker('image-processor.js');
worker.postMessage({ file, quality: 0.8 });
worker.onmessage = (e) => {
// 处理压缩后的图片
uploadFile(e.data.compressedFile);
};
// image-processor.js
self.onmessage = async (e) => {
const { file, quality } = e.data;
const compressedFile = await compressImage(file, quality);
self.postMessage({ compressedFile });
};
9. 使用现代API
利用现代浏览器提供的API提升性能:
// 使用 Promise.allSettled 处理部分失败的情况
async function uploadAll(files) {
const uploadPromises = Array.from(files).map(file => uploadFile(file));
const results = await Promise.allSettled(uploadPromises);
const successful = results.filter(result => result.status === 'fulfilled');
const failed = results.filter(result => result.status === 'rejected');
return { successful, failed };
}
10. 内存管理
及时释放不需要的对象和URL引用:
function cleanupObjectURL(url) {
URL.revokeObjectURL(url);
}
// 在图片预览后,适时清理
const objectURL = URL.createObjectURL(file);
// 使用完后
cleanupObjectURL(objectURL);
4562

被折叠的 条评论
为什么被折叠?



