Files
xyzw_web_helper/MD说明文件夹/bin文件上传速度优化方案v3.14.2.md
2025-10-17 20:56:50 +08:00

11 KiB
Raw Blame History

bin文件上传速度优化方案 v3.14.2

版本: v3.14.2
日期: 2025-10-12
类型: 性能优化


📊 性能瓶颈分析

当前性能数据

单文件处理时间~1200-3800ms

步骤 耗时 占比 类型
1. 读取文件 5-10ms <1% I/O
2. Base64转换 20-50ms 2-4% CPU
3. 读取localStorage 10-20ms 1-2% I/O
4. 写入localStorage(bin) 50-100ms 4-8% I/O
5. 上传到服务器 500-2000ms 40-50% 网络 🔴
6. 等待服务器响应 500-1500ms 30-40% 网络 🔴
7. 提取Token 5ms <1% CPU
8. 写入localStorage(Token) 30-50ms 2-4% I/O

🔴 主要瓶颈

  1. 网络请求70-90% - 服务器往返时间
  2. localStorage写入6-12% - 频繁的磁盘I/O
  3. Base64转换2-4% - CPU计算

🚀 优化方案

方案1并发上传最有效

原理:同时处理多个文件,利用网络等待时间

实现

// 并发处理配置
const CONCURRENT_UPLOAD_LIMIT = 3  // 同时上传3个文件

// 使用Promise.all控制并发
const uploadBatch = async (files, startIndex, batchSize) => {
  const batch = files.slice(startIndex, startIndex + batchSize)
  const promises = batch.map(file => uploadSingleFile(file))
  return await Promise.all(promises)
}

// 分批并发处理
for (let i = 0; i < files.length; i += CONCURRENT_UPLOAD_LIMIT) {
  await uploadBatch(files, i, CONCURRENT_UPLOAD_LIMIT)
}

预期效果

  • 3个并发速度提升 2-2.5倍 🚀
  • 9个文件从 ~18-34秒 → ~7-14秒

风险

  • ⚠️ 服务器可能有并发限制
  • ⚠️ 需要处理并发失败的情况

方案2延迟bin文件存储中等有效

原理先上传获取Token后台异步存储bin文件

实现

// 收集需要存储的bin文件
const pendingBinFiles = []

for (let file of files) {
  // 1. 快速上传获取Token
  const token = await uploadAndGetToken(file)
  tokenStore.addToken(token)
  
  // 2. 延迟存储bin文件
  pendingBinFiles.push({ id, content, ...meta })
}

// 所有上传完成后批量存储bin文件
setTimeout(() => {
  saveBinFilesToLocalStorage(pendingBinFiles)
}, 1000)

预期效果

  • 每个文件节省 50-100ms
  • 9个文件节省 ~0.5-1秒
  • 用户感知速度提升 10-15%

优点

  • 不阻塞主流程
  • 用户体验更流畅

方案3可选bin文件存储小幅优化

原理让用户选择是否需要存储bin文件

实现

<n-checkbox v-model:checked="saveBinFiles">
  保存bin文件到本地用于后续刷新Token
</n-checkbox>

预期效果

  • 如果不保存:每个文件节省 50-120ms
  • 9个文件节省 ~0.5-1.1秒
  • 速度提升 8-12%

适用场景

  • 用户不需要刷新Token功能
  • 临时导入Token

方案4批量localStorage操作小幅优化

原理减少localStorage写入次数

当前

// 每个文件写2次localStorage
for (let file of files) {
  // 写入1存储bin文件
  localStorage.setItem('storedBinFiles', ...)
  
  // 写入2存储Token
  tokenStore.addToken(...)  // 内部也会写localStorage
}
// 总计9个文件 = 18次写入

优化后

// 收集所有数据
const binFiles = []
const tokens = []

for (let file of files) {
  binFiles.push(...)
  tokens.push(...)
}

// 批量写入2次
localStorage.setItem('storedBinFiles', JSON.stringify(binFiles))
localStorage.setItem('gameTokens', JSON.stringify(tokens))
// 总计只写2次

预期效果

  • 减少16次localStorage写入
  • 节省 ~0.5-1秒
  • 速度提升 8-10%

📋 推荐实施方案

阶段1快速见效推荐优先实施 🔥

方案1 + 方案2组合

优化项 预期提升 实施难度 风险
并发上传(3并发) 120-150%
延迟bin存储 10-15% 极低
综合效果 2-2.8倍

预期结果

  • 9个文件18-34秒 → 6-12秒 🚀
  • 用户体验:显著提升

阶段2进一步优化可选

+ 方案3 + 方案4

优化项 额外提升 实施难度
可选bin存储 8-12%
批量localStorage 8-10%
综合额外效果 15-20%

最终结果

  • 9个文件18-34秒 → 5-10秒 🚀🚀
  • 用户体验:极大提升

🔧 具体实施代码

1. 并发上传实现

// 并发上传配置(可调整)
const uploadConfig = reactive({
  concurrentLimit: 3,  // 同时上传3个文件
  enableConcurrent: true  // 是否启用并发
})

// 单个文件上传函数
const uploadSingleFile = async (file, index, totalFiles) => {
  try {
    updateUploadProgress(index + 1, totalFiles, file.name)
    
    // 读取文件
    const arrayBuffer = await readBinFile(file)
    
    // 上传到服务器(最耗时的部分)
    const response = await fetch('https://xxz-xyzw.hortorgames.com/login/authuser?_seq=1', {
      method: 'POST',
      headers: { 'Content-Type': 'application/octet-stream' },
      body: arrayBuffer
    })
    
    // 提取Token
    const responseArrayBuffer = await response.arrayBuffer()
    const roleToken = extractRoleToken(responseArrayBuffer)
    
    // 生成Token数据
    const tokenData = createTokenData(roleToken, file.name)
    
    // 返回结果
    return { success: true, tokenData, arrayBuffer, file }
  } catch (error) {
    return { success: false, error, file }
  }
}

// 并发批量处理
const handleBinImportConcurrent = async () => {
  const files = binForm.files
  const totalFiles = files.length
  
  uploadProgress.show = true
  uploadProgress.type = 'bin'
  uploadProgress.total = totalFiles
  
  let successCount = 0
  let failedCount = 0
  const binFilesToSave = []  // 延迟存储
  
  // 分批并发处理
  for (let i = 0; i < files.length; i += uploadConfig.concurrentLimit) {
    const batchSize = Math.min(uploadConfig.concurrentLimit, files.length - i)
    const batch = Array.from({ length: batchSize }, (_, j) => files[i + j])
    
    // 并发上传这一批
    const results = await Promise.all(
      batch.map((file, j) => uploadSingleFile(file, i + j, totalFiles))
    )
    
    // 处理结果
    for (const result of results) {
      if (result.success) {
        // 立即保存Token
        tokenStore.addToken(result.tokenData)
        successCount++
        uploadProgress.successCount = successCount
        
        // 收集bin文件延迟存储
        binFilesToSave.push({
          id: `bin_${Date.now()}_${Math.random()}`,
          name: result.file.name,
          content: arrayBufferToBase64(result.arrayBuffer),
          tokenData: result.tokenData
        })
      } else {
        failedCount++
        uploadProgress.failedCount = failedCount
        console.error(`上传失败: ${result.file.name}`, result.error)
      }
    }
  }
  
  // 后台异步存储bin文件不阻塞
  setTimeout(() => {
    saveBinFilesToLocalStorage(binFilesToSave)
  }, 500)
  
  // 显示结果
  setTimeout(() => resetUploadProgress(), 2000)
  message.success(`成功导入 ${successCount} 个Token${failedCount > 0 ? `${failedCount} 个失败` : ''}`)
}

// 批量保存bin文件到localStorage
const saveBinFilesToLocalStorage = (binFiles) => {
  try {
    const storedBinFiles = JSON.parse(localStorage.getItem('storedBinFiles') || '{}')
    
    // 批量添加
    binFiles.forEach(binFile => {
      storedBinFiles[binFile.id] = {
        id: binFile.id,
        name: binFile.name,
        roleName: binFile.tokenData.name,
        content: binFile.content,
        createdAt: new Date().toISOString(),
        lastUsed: new Date().toISOString()
      }
    })
    
    // 一次性写入
    localStorage.setItem('storedBinFiles', JSON.stringify(storedBinFiles))
    console.log(`✅ 批量保存 ${binFiles.length} 个bin文件到localStorage`)
  } catch (error) {
    console.error('批量保存bin文件失败:', error)
  }
}

2. 可选bin文件存储

<template>
  <n-form-item label="上传选项">
    <n-space vertical>
      <n-checkbox v-model:checked="uploadConfig.enableConcurrent">
        <n-text>启用并发上传推荐速度提升2-3</n-text>
      </n-checkbox>
      
      <n-checkbox v-model:checked="uploadConfig.saveBinFiles">
        <n-text>保存bin文件到本地用于后续刷新Token</n-text>
      </n-checkbox>
      
      <n-input-number 
        v-if="uploadConfig.enableConcurrent"
        v-model:value="uploadConfig.concurrentLimit"
        :min="1"
        :max="5"
        placeholder="并发数量"
      >
        <template #prefix>并发数</template>
      </n-input-number>
    </n-space>
  </n-form-item>
</template>

<script setup>
const uploadConfig = reactive({
  enableConcurrent: true,   // 默认启用
  concurrentLimit: 3,       // 默认3个并发
  saveBinFiles: true        // 默认保存
})
</script>

📈 性能对比

测试场景上传9个bin文件

版本 串行/并发 bin存储 总耗时 速度提升
v3.14.1 串行 即时 18-34秒 基线
v3.14.2-A 3并发 即时 7-14秒 2.2x 🚀
v3.14.2-B 3并发 延迟 6-12秒 2.5x 🚀
v3.14.2-C 3并发 可选关闭 5-10秒 2.8x 🚀🚀

实际体验

  • v3.14.1等待18-34秒用户感觉很慢 😟
  • v3.14.2等待5-10秒用户感觉很快 😊

⚠️ 注意事项

1. 服务器并发限制

某些服务器可能限制同一IP的并发请求数建议

  • 默认3个并发安全
  • 最多不超过5个
  • 如果遇到429错误自动降低并发数

2. 浏览器资源

  • 浏览器对同一域名的并发连接数有限制通常6-10个
  • 建议并发数不超过3-4个

3. 错误处理

并发模式下需要更完善的错误处理:

try {
  const results = await Promise.all(batch)
} catch (error) {
  // 某个文件失败不影响其他文件
  console.error('批次处理失败:', error)
}

4. 内存占用

并发处理会同时占用更多内存:

  • 3个并发增加约10-20MB内存
  • 可接受范围

实施建议

推荐配置

// 推荐的默认配置
{
  enableConcurrent: true,     // 启用并发
  concurrentLimit: 3,         // 3个并发平衡性能和稳定性
  saveBinFiles: true,         // 保存bin文件功能完整
  delaySaveBinFiles: true     // 延迟保存(提升速度)
}

渐进式实施

  1. 第一步实施并发上传方案1

    • 风险低,收益高
    • 测试稳定性
  2. 第二步添加延迟存储方案2

    • 进一步优化
    • 观察用户反馈
  3. 第三步添加可选配置方案3

    • 给高级用户更多选择
    • 完善体验

版本标记: v3.14.2
实施状态: 待实施
预期收益: 速度提升 2-2.8倍 🚀🚀