记录--记录用前端代替后端生成zip的过程,速度快了 57 倍!!!

这篇具有很好参考价值的文章主要介绍了记录--记录用前端代替后端生成zip的过程,速度快了 57 倍!!!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

记录--记录用前端代替后端生成zip的过程,速度快了 57 倍!!!

业务场景:

产品有个功能是设置主题。类似手机自动切换壁纸,以及其他功能颜色,icon,字体等。

管理员需要在后端管理系统多次下载不同主题,(至于要干啥就不说了...),主题中可能有 30 ~ 100个高清壁纸, icon 等。现在每次下载主题(31张高清图片)至少需要 10s。有什么方法能够优化下。

因为代码不具备可复用性,因此部分代码直接省略,思路为主

原始逻辑

  public async getZip(themeId: string, res: any) {
    const theme = await this.model.findById(themeId); // 从数据库

    // 这里需要借用一个服务器上的主题模板文件夹 template/,
    
    /*
       theme = {
              wallpapers: [
                  { url: 'https://亚马逊云.com/1.jpg', ... },
                  ...
              ]
       }
    */
    
    // for 循环遍历 theme.wallpapers , 并通过 fetch 请求 url,将其写进 template/static/wallpapers 文件夹中
    theme.wallpapers.map((item) => {
        const response = await fetch(item.url);
        const buffer = new Uint8Array(await response.arrayBuffer());
        await fs.writeFile(`template/wallpapers/${fileName}`, buffer);
    })
    
    // ... 还有其他一些处理
    
    // 将 template 压缩成 zip 文件,发送给前端
  }

思考 ing ...

1 利用图片可以被浏览器缓存

当一次下载主题从请求亚马逊云的图片数据,这步没有问题。 但是当重复下载的时候,之前下载过的图片又会再次下载,操作人员每次都需要等个十几秒,这就不太友好了。这部分时间花费还是挺多的。

可以利用下浏览器能够将图片缓存到 disk cache 中的特点,将这部分的代码逻辑放到前端完成,因为还需要对压缩包中的文件做一些处理,因此需要借助下 jszip 这个库。

看下改后的代码

onDownload () {
    // 请求拿到 theme 数据
    const theme = api.getTheme() 
    const template = api.getTemplate() // Blob
    
    const zip = new JSZip()
    await zip.loadAsync(getTmplResp) // 读取 template.zip 文件数据
    
    console.time('handle images')
    const wallpaperList = theme.wallpapers
    for (const wallpaper of wallpaperList) {
      const response = await fetch(wallpaper.url) // 请求图片数据
      const buffer = new Uint8Array(await response.arrayBuffer())
      const fileName = wallpaper.url.split('/').pop()
      zip.file(`static/wallpapers/${fileName}`, buffer, { binary: true }) // 写进压缩包
    }
    console.timeEnd('handle images') // 统计用时
    
    // 还需要读取 template.zip 中的 config.json, 然后修改,重新保存到 template.zip 中
    ...
    
    // 导出 template.zip
    zip.generateAsync({ type: 'base64' }).then(
      (base64) => {
        const link = document.createElement('a')
        link.href = 'data:application/zip;base64,' + base64
        link.download = 'template.zip'
        link.target = '_blank'
        link.style.display = 'none'

        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
      },
      (err) => {
        console.log('打包失败', err)
      }
    )
}

优化完成

当第一次下载时,handle images 步骤耗时 20 - 21 s,流程和后端差不多。

当第二次下载时,handle images 步骤耗时 0.35s - 0.45 s。会直接读取 disk cache 中的图片数据,50 ms 内就完成了。

速度快了 57 倍有余!!!, 你还能想到其他优化方式吗?继续往后看 🍒

第一次请求各个图片耗时

记录--记录用前端代替后端生成zip的过程,速度快了 57 倍!!!

 第二次请求各个图片耗时

记录--记录用前端代替后端生成zip的过程,速度快了 57 倍!!!

2 并发请求

我们都知道,浏览器会为每个域名维持 6 个 TCP 链接(再拓展还有域名分片知识),我们是否可以利用这个特点做些什么?

答案是:并发上传

通过上面的代码,可以看到,每个图片请求都是串行的,一个图片请求完了再进行下一个图片请求。我们一次请求 4 个图片,这样就更快了。

首先写一个能够管理并发任务的类

export class TaskQueue {
  public queue: {
    task: <T>() => Promise<T>
    resolve: (value: unknown) => void
    reject: (reason?: any) => void
  }[]
  public runningCount: number  // 正在执行的任务数量
  public tasksResloved?: (value: unknown) => void
  public tasksRejected?: (reason?: any) => void

  public constructor(public maxConcurrency: number = 4) { // 最多同时执行 4 个任务
    this.queue = [] // 任务队列
    this.runningCount = 0
  }
  
  // 添加任务
  public addTask(task) {
    return new Promise((resolve, reject) => {
      this.queue.push({ task, resolve, reject })
    })
  }
    
  // 执行
  public run() {
    return new Promise((resoved, rejected) => {
      this.tasksResloved = resoved
      this.tasksRejected = rejected
      this.nextTask()
    })
  }

  private nextTask() {
    if (this.queue.length === 0 && this.runningCount === 0) {
      this.tasksResloved?.('done')
      return
    }
    
    // 如果任务队列中还有任务, 并且没有到最大执行任务数,就继续取出任务执行
    while (this.queue.length > 0 && this.runningCount < this.maxConcurrency) {
      const { task, resolve, reject } = this.queue.shift()
      this.runningCount++
      task()
        .then((res) => {
          this.runningCount--
          resolve(res)
          this.nextTask()
        })
        .catch((e) => {
          this.runningCount--
          reject(e)
          this.nextTask()
        })
    }
  }
}

改造代码

onDownload () {
    // 请求拿到 theme 数据
    const theme = api.getTheme() 
    const template = api.getTemplate() // Blob
    
    const zip = new JSZip()
    await zip.loadAsync(getTmplResp) // 读取 template.zip 文件数据
    
    console.time('handle images')
    const wallpaperList = theme.wallpapers
    
    // 注释之前的逻辑
    // for (const wallpaper of wallpaperList) {
    //   const response = await fetch(wallpaper.url) 
    //   const buffer = new Uint8Array(await response.arrayBuffer())
    //   const fileName = wallpaper.url.split('/').pop()
    //   zip.file(`static/wallpapers/${fileName}`, buffer, { binary: true }) 
    // }
    
    const taskQueue = new TaskQueue() // 新建任务队列,默认同时执行 4 个
    for (const wallpaper of wallpaperList) {
      taskQueue
        .addTask(() => fetch(wallpaper.url)) // 添加任务
        .then(async (res) => {  // 任务执行完后的回调
          const buffer = new Uint8Array(await (res as Response).arrayBuffer())
          const fileName = wallpaper.url.split('/').pop()
          zip.file(`static/wallpapers/${fileName}`, buffer, { binary: true })
        })
        .catch((e) => console.log('壁纸获取失败', e))
    }
    await taskQueue.run()  // 等待所有图片都拿到
    console.timeEnd('handle images') // 统计用时
    
    // 还需要读取 template.zip 中的 config.json, 然后修改,重新保存到 template.zip 中
    ...
    
    // 导出 template.zip
    zip.generateAsync({ type: 'base64' }).then(
      (base64) => {
        const link = document.createElement('a')
        link.href = 'data:application/zip;base64,' + base64
        link.download = 'template.zip'
        link.target = '_blank'
        link.style.display = 'none'

        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
      },
      (err) => {
        console.log('打包失败', err)
      }
    )
}

大功告成!

当第一次下载时,handle images 步骤耗时 7 s,速度是之前的 3 倍。

当第二次下载时,handle images 步骤耗时 0.25s,速度是之前的 1.4 - 1.8

3 更多的可能

越来越感觉到计算机网络的重要性, 还有未实现的优化方式:

  1. 域名分片,更多的并发(也有劣势 ,比如 每个域都需要额外的 DNS 查找成本以及建立每个 TCP 连接的开销, TCP 慢启动带宽利用不足)
  2. 升级 HTTP2 这不是靠前端一人能够完成的

本文转载于:

https://juejin.cn/post/7267418197746270271

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 记录--记录用前端代替后端生成zip的过程,速度快了 57 倍!!!文章来源地址https://www.toymoban.com/news/detail-711275.html

到了这里,关于记录--记录用前端代替后端生成zip的过程,速度快了 57 倍!!!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 并行环境让采样速度快两个量级:Isaac Gym提速强化学习

    仿真环境的 采样速度慢 ,是强化学习的一个瓶颈。例如,论文中常用的 MuJoCo 环境,台式机或服务器的 CPU 上运行仿真环境,一小时大概采集十万或百万步(1e5 或 1e6 步);训练一个智能体(收敛后)需要十多个小时。 加快仿真环境的采样速度,通常有以下方法: 增加并行

    2024年02月16日
    浏览(34)
  • 一个操作让数组处理速度快了5倍,到底是为什么

      概述: 通过对数组进行排序,代码更好地利用了缓存,从而提高了程序的性能。这种现象通常被称为\\\"缓存友好\\\"(cache-friendly)或\\\"空间局部性\\\"(spatial locality) 今天做一个数组数据计算时,发现一个效率问题,给大家分享一下 一个数组排序和不排序时同样的逻辑处理速度是

    2024年03月24日
    浏览(43)
  • 分享三个转换速度快、准确率高的视频转文字工具

    想要直接将视频转换成文字,转换工具很重要!给大家分享三个转换速度快、准确率高的视频转文字工具,轻松完成转换。 1.网易见外 https://sight.youdao.com/ 网易家的智能转写翻译服务工作站,网页端就可以直接使用,支持视频翻译、转写,语音翻译、转写,会议同传、文档翻

    2024年04月26日
    浏览(26)
  • Kafka必须掌握的核心技术:为什么吞吐量大、速度快?

    如果不删除硬盘肯定会被撑满,所以Kakfa提供了两种策略来删除数据。一是基于时间,二是基于partition文件大小。具体配置可以参看它的配置文档。 二、Page Cache 为了优化读写性能,Kafka利用了操作系统本身的Page Cache,就是利用操作系统自身的内存而不是JVM空间内存。这样做

    2024年04月08日
    浏览(41)
  • 前端调接口下载(导出)后端返回.zip压缩文件流(的坑!)

    前言:基于vue2+element-ui的一个后台管理系统,需求评审要加一个导入导出文件的功能,由于可能导出的数据量过大(几十万条数据),下载时间过长,所以用.zip压缩文件替代excel文件 本人以前也做过导出文件的功能,但是用的方法是后端处理数据然后放到另一个服务器上,前

    2024年02月03日
    浏览(34)
  • yolov8 瑞芯微 RKNN 的 C++部署,部署工程难度小、模型推理速度快

       之前写过两次yolov8目标检测部署,后续继续思考,针对部署还有优化空间,本示例的部署方式优化了部署难度,加快了模型推理速度(略微增加了后处理的时耗)。 特别说明:如有侵权告知删除,谢谢。 【完整代码】代码和模型    onnx转rknn模型这一步就不再赘述,请

    2024年01月23日
    浏览(30)
  • 二挡起步——pythonweb开发Django框架,前端原生+Django后端框架+python网络抓包(代替数据库数据)(附带小案例)

     大家好,我是csdn的博主: lqj_本人 这是我的个人博客主页: lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主 lqj_本人擅长微信小程序,前端,python,等方面的知识 https://blog.csdn.net/lbcyllqj?spm=1011.2415.3001.5343 哔哩哔哩欢迎关注: 小淼Develop 小淼Develop的个人空间-小淼Develop个

    2024年02月03日
    浏览(53)
  • yolov8n 瑞芯微RKNN和地平线Horizon芯片仿真测试部署,部署工程难度小、模型推理速度快

      特别说明:参考官方开源的yolov8代码、瑞芯微官方文档、地平线的官方文档,如有侵权告知删,谢谢。   模型和完整仿真测试代码,放在github上参考链接 模型和代码。   因为之前写了几篇yolov8模型部署的博文,存在两个问题:部署难度大、模型推理速度慢。该篇解

    2024年02月01日
    浏览(37)
  • yolov8n 瑞芯微RKNN、地平线Horizon芯片部署、TensorRT部署,部署工程难度小、模型推理速度快

      特别说明:参考官方开源的yolov8代码、瑞芯微官方文档、地平线的官方文档,如有侵权告知删,谢谢。   模型和完整仿真测试代码,放在github上参考链接 模型和代码。   因为之前写了几篇yolov8模型部署的博文,存在两个问题:部署难度大、模型推理速度慢。该篇解

    2024年01月16日
    浏览(51)
  • 何恺明团队12页论文新作剑指AIGC!“新CLIP”只需一个trick,训练速度快3.7倍!性能不降反升...

    杨净 艳艳 发自 凹非寺 量子位 | 公众号 QbitAI 何恺明团队又上新了。 这次,他们的成果围绕当下最火的AIGC背后的CLIP展开。 ——只在该模型的极简结构上,施加了一个简单的mask,就让新模型的速度快了3.7倍。 同时,性能还可以做到 不降反升 。 团队表示,希望他们的工作能

    2024年02月11日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包