canvas 的动画卡顿问题(运行一段时间卡顿)
关于canvas动画越来越卡的问题
最近公司有项目需要写纯canvas组件,所以花了一段时间学习了下canvas。 canvas这东西上手简单,精通难。而且也很少纯canvas写,所以网上参考的内容也比较少。
这里记录我用canvas遇到的一个坑,canvas运行一段时间卡顿。
为了给你们省时间,我先直接放解决办法。想看问题分析的步骤和方法可以看下去。
canvas中使用的save()
数量和restore()
的数量一致就能解决问题。 记得点个赞再走
问题描述:
canvas写的动画效果,刚运行是很正常,但是一段时间(差不多2分钟)后速度会很慢,这里直接上图看效果。
刚运行时:
运行一段时间(差不多2分钟)后
对,你没看错,这就是现在的运行速度
可以看到,运行一段时间后,速度变得非常慢,那么先分析下代码:
<template>
<div class="round">
<canvas id="round" width="500" height="500"></canvas>
</div>
</template>
<script>
export default {
name: "round",
data() {
return {
radian: 10, //弧度
}
},
mounted() {
this.draw()
},
methods: {
draw() {
// 以下变量都不能修改
let tx = 0
let isbig = true
let arcRound = 0
let arcRound1 = 0
let arcRound2 = 0
let alpha = 0
/** @type {HTMLCanvasElement} */
const round = document.getElementById("round")
const ctx = round.getContext("2d")
let name = () => {
alpha += 0.008
ctx.globalAlpha = alpha
ctx.save()
ctx.clearRect(0, 0, round.clientWidth, round.clientHeight)
//动画
if (isbig) {
tx = tx + 1
} else {
tx = tx - 0.3
}
// 大圈
ctx.beginPath()
ctx.strokeStyle = "#5a7cfb"
ctx.lineWidth = 3
ctx.translate(round.clientWidth / 2, round.clientHeight / 2)
ctx.rotate(((arcRound = 0.4 + arcRound) * Math.PI) / 180)
ctx.arc(0, 0, (round.clientHeight / 100) * 50, 0, Math.PI * 2)
ctx.setLineDash([50, 150, 50])
ctx.stroke()
ctx.restore()
ctx.save()
// 中圈
ctx.beginPath()
ctx.strokeStyle = "#5a7cfb"
ctx.lineWidth = 3
ctx.translate(round.clientWidth / 2, round.clientHeight / 2)
ctx.rotate(((arcRound1 = arcRound1 - 0.5) * Math.PI) / 180)
ctx.arc(0, 0, (round.clientHeight / 100) * 48, 0, Math.PI * 2)
ctx.setLineDash([2, 80, 50])
ctx.stroke()
ctx.restore()
ctx.save()
// 小圈
ctx.beginPath()
ctx.strokeStyle = "#5a7cfb"
ctx.lineWidth = 3
ctx.translate(round.clientWidth / 2, round.clientHeight / 2)
ctx.rotate(((arcRound2 = arcRound2 + 0.15) * Math.PI) / 180)
ctx.arc(0, 0, (round.clientHeight / 100) * 46, 0, Math.PI * 2)
ctx.setLineDash([50, 150, 80])
ctx.stroke()
ctx.restore()
ctx.save()
// 小圈
ctx.beginPath()
ctx.strokeStyle = "#5a7cfb70"
ctx.lineWidth = 1.5
ctx.translate(round.clientWidth / 2, round.clientHeight / 2)
ctx.rotate(((arcRound2 / 2) * Math.PI) / 180)
ctx.arc(0, 0, (round.clientHeight / 100) * 46, 0, Math.PI * 2)
ctx.setLineDash([70, 60])
ctx.stroke()
ctx.restore()
ctx.save()
window.requestAnimationFrame(name)
}
window.requestAnimationFrame(name)
},
},
}
</script>
<style scoped>
#round {
background-color: #333;
}
</style>
解决这个问题,起初时没有任何头绪,翻阅百度谷歌都没有找到解决办法,只好自己又去分析问题。
分析问题:
恰巧,分析问题分析到块下班了,准备关电脑下班了,结果,在关闭浏览器标签页的时候发现了问题,平常点击关闭按钮就会瞬间关闭的标签页,在我关闭正在写的页面的时候居然卡了2秒左右才关闭,我又打开页面试了下发现,页面刚打开是关闭,时瞬间关闭的,但是运行到canvas动画速度变慢的时候关闭,就会出现先卡顿一下再关闭的情况。
所以,我就看了下浏览器的性能占用,下面直接放图。 刚运行时的内存占用:30MB
然后我看着从30MB一路上升到接近80MB的内存占用,陷入可沉思。 运行一段时间后的内存占用:30MB
我好像发现了原因,是内存爆了。我以为是window.requestAnimationFrame
搞的鬼,然后就在该次动画运行后,下次动画运行前用window.cancelAnimationFrame
停掉了该次动画,结果还是无济于事。我又想,难道canvas有什么方法会把参数写到内存?等等,save()
不就是吗?看下官方文档。
好家伙,应该就是你搞的鬼了。 save()
的作用是把参数写到栈内存种,需要的时候用restore()
拿取。所以就是我放入内存的参数大于我拿取的参数,导致内存爆了?试一试就知道了。 我发现在上面的代码中用了5个save()
,但是restore()
只用了4个。我删掉了最下面的ctx.save()
,在运行一段时间看看内存变化。
这下内存占用稳定到了20MB左右,CPU占用也从30%直接掉到了2%。我又让动画运行了20多分钟,依然没有变慢,好了,大功告成,问题就是save()
引起的了,只要放入内存的参数(save()
)数量和拿取的参数restore()
数量一致,就不会出现相同的问题。
代码写的可能不是很规范,而且我也还是个新手,大佬饶命
更多推荐
所有评论(0)