0

我正在开发一个大量使用 canvas 元素的 HTML5 游戏。有一个持续的事件循环更新主画布元素,然后需要定期对其进行重大更改。基本上,随着角色四处移动,背景会更新。发生这种情况时会出现明显的停顿,因此我尝试使用异步函数执行操作,但我似乎受到了完全相同的性能影响。我已经尝试在异步函数中对不可见的画布执行所有操作,然后在事件循环中完成后将其复制到主画布,但同样没有提高性能。

我编写了这个荒谬的小程序,它似乎重复了我正在谈论的行为。似乎捆绑画布元素,即使在异步函数中,也会影响程序的其余部分。

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var ImDat=ctx.createImageData(1000,1000);
var ticker = 0;

ImDat.setPixel=function(x,y,c){
   var i=(x+y*this.width)*4;
   this.data[i]=c.R;
   this.data[i+1]=c.G;
   this.data[i+2]=c.B;
   this.data[i+3]=c.A;
}

var bigOperation = function() {
   for (var i = 0; i < 20; i++) {
      lilOperation();
   }
   console.log(new Date + 'big op done');
}

var lilOperation = function() {
   for (var i = 0; i < canvas.width; i++) {
      for (var j = 0; j < canvas.height; j++) {
         ImDat.setPixel(i, j, { R: Math.random() * 256, G: Math.random() * 256, B: Math.random() * 256, A: 256 });
      }
   }
   ctx.putImageData(ImDat, 0, 0);
}

var eventLoop = function() {
   if (ticker == 50) {
      ticker = 0;
      console.log(new Date + 'big op start'); 
      window.setTimeout(bigOperation, 1);                     
   } else {
      ticker++;
   }
      lilOperation();
      console.log(new Date + 'normal loop');  
}

window.setInterval(eventLoop, 10);

因此,您会注意到在调用 bigOperation 函数之前记录了一致的时间间隔,此时事件循环会暂停片刻。请注意,我正在一个非常糟糕的系统上进行此操作,因此您可能必须增加 bigOperation 中的迭代次数才能获得效果。

谢谢!

4

1 回答 1

1

即使您使用 setTimeout,执行也会锁定所有内容,直到函数调用完成,这只是 Javascript 的本质。这实际上是一种祝福而不是一种诅咒,因为它大大简化了事情。

由于 Javascript 的单线程特性,发明了一种称为“Web Workers”的东西。这是浏览器中一个相对较新的功能,但它允许您执行单独运行的任务而无需锁定主线程。在现代浏览器中,您可以使用 web workers 执行画布任务

现在,在对您的游戏一无所知的情况下,听起来您想要实现的目标(更新背景图形、移动角色等)应该是可能的,而无需调用需要很长时间才能执行的繁重函数。您是否在执行大量每像素操作?如果是这样,他们不能通过其他方式完成吗?在考虑使用网络工作者之前,我实际上会开始考虑优化你的代码。

于 2012-10-06T23:20:43.780 回答