大量图片一次性上传,前端优化方式

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);
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

香蕉可乐荷包蛋

努力写有用的code

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值