海报分享中使用HTML2Canvas的优化

背景

日常需求中能遇见需要用户保存海报,然后分享海报到微信的场景

此时我们的背景是:利用一个v-for。循环出N个div,一个div就是一张海报。

最初的做法是,串行执行转换,用一个for循环,挨个去转换每一个div,总共要执行n次。我们测试都是五张海报,大概需要九秒。

后续去做优化:

很明显的能想到:第一个优化的方法是。并行执行,大概需要5秒

但是还是不够满足要求:

后续去看了很多文章+HTML2Canvas的官网,想到:其实最耗费时间的事情,是转换,我们转换的次数太多了。为何不合并在一起呢,这样的话,只需要一次转换,后续切割就可以了

然后我去做了优化,把五张海报上下合并在一起,然后一次性转换一个很长的海报,然后很长的海报拿到后,进行切割,因为每张海报都是等长的,所以只用根据高度来切割就行,然后大概需要2.7秒。在五张海报的情况下优化了6.3秒

转换代码

const allPosterBox = ref<HTMLDivElement>(null as unknown as HTMLDivElement)
async function save() {
  if (saveLocked) return
  showLoading('保存中')

  const arr: string[] = []
  const canvas = await html2canvas(allPosterBox.value, { useCORS: true })
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
  const context = canvas.getContext('2d')!
  // 图片宽高 375 * 644
  const imgHeight = canvas.width * 644 / 375
  for (let i = 0; i < selectedInfoList.value.length; i++) {
    const imageData = context.getImageData(0, i * imgHeight, canvas.width, imgHeight)
    const newImageData = context.createImageData(imageData.width, imageData.height)
    newImageData.data.set(imageData.data)
    const newCanvas = document.createElement('canvas')
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const newCtx = newCanvas.getContext('2d')!
    newCanvas.width = imageData.width
    newCanvas.height = imageData.height
    newCtx.putImageData(newImageData, 0, 0)
    const base64Image = newCanvas.toDataURL('image/jpeg', 0.6)
    arr.push(base64Image.split(';base64,')[1])
  }

  const list: Promise<{ url: string }>[] = []
  for (let i = 0; i < arr.length; i++) {
    list.push(uploadImg({ content: arr[i] }))
  }

  Promise.all(list).then(async res => {
    for (let i = 0; i < res.length; i++) {
      await new Promise((resolve) => {
        bridge.saveImage({
          type: 1, // 1:url  2:base64
          data: res[i].url
        }, (res) => {
          if (Number(res.errno) === 0) {
            resolve(true)
          } else {
            throw new Error()
          }
        })
      })
    }
    step.value = 'create'
    saveLocked = false
    hideToast()
    showToast('保存成功', 'correct')
  }).catch((err) => {
    saveLocked = false
    console.log(err)
    showToast('保存全部失败')
  })
}

成长

对于这块,我的收获是:做性能优化的时候,最关键的是找到哪里才是最耗费性能的,例如我最初以为是串行占了并行时间,其实最后发现是转换占了时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值