您现在的位置是:网站首页> 编程资料编程资料

浅谈利用缓存来优化HTML5 Canvas程序的性能一张图看懂移动HTML5前端性能优化

2021-08-31 1066人已围观

简介 这篇文章主要介绍了浅谈利用缓存来优化HTML5 Canvas程序的性能,并且作者给出了使用缓存以及离屏Canvas后性能较原程序的提升对比,需要的朋友可以参考下

canvas玩多了后,就会自动的要开始考虑性能问题了。怎么优化canvas的动画呢?

  【使用缓存】

  使用缓存也就是用离屏canvas进行预渲染了,原理很简单,就是先绘制到一个离屏canvas中,然后再通过drawImage把离屏canvas画到主canvas中。可能看到这很多人就会误解,这不是写游戏里面用的很多的双缓冲机制么?

  其实不然,双缓冲机制是游戏编程中为了防止画面闪烁,因此会有一个显示在用户面前的画布以及一个后台画布,进行绘制时会先将画面内容绘制到后台画布中,再将后台画布里的数据绘制到前台画布中。这就是双缓冲,但是canvas中是没有双缓冲的,因为现代浏览器基本上都是内置了双缓冲机制。所以,使用离屏canvas并不是双缓冲,而是把离屏canvas当成一个缓存区。把需要重复绘制的画面数据进行缓存起来,减少调用canvas的API的消耗。

  众所周知,调用canvas的API很消耗性能,所以,当我们要绘制一些重复的画面数据时,妥善利用离屏canvas对性能方面有很大的提升,可以看下下面的DEMO

  1 、 没使用缓存   

  2、  使用了缓存但是没有设置离屏canvas的宽高  

      3 、 使用了缓存但是没有设置离屏canvas的宽高  

  4 、 使用了缓存且设置了离屏canvas的宽高

  可以看到上面的DEMO的性能不一样,下面分析一下原因:为了实现每个圈的样式,所以绘制圈圈时我用了循环绘制,如果没用启用缓存,当页面的圈圈数量达到一定时,动画每一帧就要大量调用canvas的API,要进行大量的计算,这样再好的浏览器也会被拖垮啦。
XML/HTML Code复制内容到剪贴板

  1. ctx.save();   
  2.                         var j=0;   
  3.                         ctx.lineWidth = borderWidth;   
  4.                         for(var i=1;i<this.r;i+=borderWidth){   
  5.                             ctx.beginPath();   
  6.                             ctx.strokeStyle = this.color[j];   
  7.                             ctx.arc(this.x , this.y , i , 0 , 2*Math.PI);   
  8.                             ctx.stroke();   
  9.                             j++;   
  10.                         }   
  11.                         ctx.restore();  

  所以,我的方法很简单,每个圈圈对象里面给他一个离屏canvas作缓存区。

  除了创建离屏canvas作为缓存之外,下面的代码中有一点很关键,就是要设置离屏canvas的宽度和高度,canvas生成后的默认大小是300X150;对于我的代码中每个缓存起来圈圈对象半径最大也就不超过80,所以300X150的大小明显会造成很多空白区域,会造成资源浪费,所以就要设置一下离屏canvas的宽度和高度,让它跟缓存起来的元素大小一致,这样也有利于提高动画性能。上面的四个demo很明显的显示出了性能差距,如果没有设置宽高,当页面超过400个圈圈对象时就会卡的不行了,而设置了宽高1000个圈圈对象也不觉得卡。

XML/HTML Code复制内容到剪贴板
  1. var ball = function(x , y , vx , vy , useCache){   
  2.                 this.x = x;   
  3.                 this.y = y;   
  4.                 this.vx = vx;   
  5.                 this.vy = vy;   
  6.                 this.r = getZ(getRandom(20,40));   
  7.                 this.color = [];   
  8.                 this.cacheCanvas = document.createElement("canvas");   
  9.                 thisthis.cacheCtx = this.cacheCanvas.getContext("2d");   
  10.                 this.cacheCanvas.width = 2*this.r;   
  11.                 this.cacheCanvas.height = 2*this.r;   
  12.                 var num = getZ(this.r/borderWidth);   
  13.                 for(var j=0;j<num;j++){   
  14.                     this.color.push("rgba("+getZ(getRandom(0,255))+","+getZ(getRandom(0,255))+","+getZ(getRandom(0,255))+",1)");   
  15.                 }   
  16.                 this.useCache = useCache;   
  17.                 if(useCache){   
  18.                     this.cache();   
  19.                 }   
  20.             }  

 

当我实例化圈圈对象时,直接调用缓存方法,把复杂的圈圈直接画到圈圈对象的离屏canvas中保存起来。

XML/HTML Code复制内容到剪贴板
  1. cache:function(){   
  2.                     this.cacheCtx.save();   
  3.                     var j=0;   
  4.                     this.cacheCtx.lineWidth = borderWidth;   
  5.                     for(var i=1;i<this.r;i+=borderWidth){   
  6.                         this.cacheCtx.beginPath();   
  7.                         thisthis.cacheCtx.strokeStyle = this.color[j];   
  8.                         this.cacheCtx.arc(this.r , this.r , i , 0 , 2*Math.PI);   
  9.                         this.cacheCtx.stroke();   
  10.                         j++;   
  11.                     }   
  12.                     this.cacheCtx.restore();   
  13.                 }  

然后在接下来的动画中,我只需要把圈圈对象的离屏canvas画到主canvas中,这样,每一帧调用的canvasAPI就只有这么一句话:

XML/HTML Code复制内容到剪贴板
  1. ctx.drawImage(this.cacheCanvas , this.x-this.r , this.y-this.r);  

跟之前的for循环绘制比起来,实在是快太多了。所以当需要重复绘制矢量图的时候或者绘制多个图片的时候,我们都可以合理利用离屏canvas来预先把画面数据缓存起来,在接下来的每一帧中就能减少很多没必要的消耗性能的操作。

下面贴出1000个圈圈对象流畅版代码:
  

XML/HTML Code复制内容到剪贴板
  1. >  
  2. <html lang="en">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <style>  
  6.         body{   
  7.             padding:0;   
  8.             margin:0;   
  9.             overflow: hidden;   
  10.         }   
  11.         #cas{   
  12.             display: block;   
  13.             background-color:rgba(0,0,0,0);   
  14.             margin:auto;   
  15.             border:1px solid;   
  16.         }   
  17.     style>  
  18.     <title>测试title>  
-六神源码网