背景
日常需求中能遇见需要用户保存海报,然后分享海报到微信的场景
此时我们的背景是:利用一个v-for。循环出N个div,一个div就是一张海报。
最初的做法是,串行执行转换,用一个for循环,挨个去转换每一个div,总共要执行n次。我们测试都是五张海报,大概需要九秒。
后续去做优化:
很明显的能想到:第一个优化的方法是。并行执行,大概需要5秒
但是还是不够满足要求:
后续去看了很多文章+HTML2Canvas的官网,想到:其实最耗费时间的事情,是转换,我们转换的次数太多了。为何不合并在一起呢,这样的话,只需要一次转换,后续切割就可以了
然后我去做了优化,把五张海报上下合并在一起,然后一次性转换一个很长的海报,然后很长的海报拿到后,进行切割,因为每张海报都是等长的,所以只用根据高度来切割就行,然后大概需要2.7秒。在五张海报的情况下优化了6.3秒
转换代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| 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 }) const context = canvas.getContext('2d')! 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') 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, 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('保存全部失败') }) }
|
成长
对于这块,我的收获是:做性能优化的时候,最关键的是找到哪里才是最耗费性能的,例如我最初以为是串行占了并行时间,其实最后发现是转换占了时间