背景
日常需求中能遇见需要用户保存海报,然后分享海报到微信的场景
此时我们的背景是:利用一个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('保存全部失败')
})
}
成长
对于这块,我的收获是:做性能优化的时候,最关键的是找到哪里才是最耗费性能的,例如我最初以为是串行占了并行时间,其实最后发现是转换占了时间