如何加快画布应用程序的速度?如何改善内存使用率?

时间:2018-09-18 02:18:14

标签: javascript html html5 canvas html5-canvas

我已经尝试学习HTML5画布了一段时间,并且编写了一个简短的脚本,该脚本允许将字符串传递到对象中,然后将其显示在画布上。但是,它的性能非常不稳定,我对其中的原因有一些想法。

使用fillRect时,使用beginPath和endPath是否会提高性能?据我所知,它们实际上仅用于行。

更重要的是,看起来好像有一些严重的内存泄漏问题,我猜想当垃圾回收开始时,就是程序停止运行。我试图阅读有关javascript如何处理内存分配的信息,但是老实说,这超出了我的理解。我在循环中没有任何变量声明(除了for循环的开始,但是我尝试更改它,但没有看到任何改善),但是我在画布上绘制的对象位于函数内部,所以也许是在做每次调用该对象时都会产生一堆新变量?

简而言之,我不知道如何使javascript工作更快并更智能地处理内存。

Here's到应用程序本身的链接。

下面是将字符串显示在画布上的代码,然后是创建对象并将显示信息传递到其中的html和js:

/* screen.js */
function screen(id, pSize, w, h) {

  var pixelSize;
  var screenWidth;
  var screenHeight;
  var canvas;
  var context;
  var palette = new Array(16);

  palette = [
    "#000000", "#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777",
    "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF"
  ];

  this.setScreenAttributes = function(pSize, w, h) {
    pixelSize = pSize;
    screenWidth = w;
    screenHeight = h;
    canvas.setAttribute("width", screenWidth * pixelSize);
    canvas.setAttribute("height", screenHeight * pixelSize);
    console.log("set screen attributes to " + screenWidth * pixelSize + "x" + screenHeight * pixelSize);
  };

  this.buildScreen = function(id, pSize, w, h) {
    canvas = document.getElementById(id);
    context = canvas.getContext("2d");
    this.setScreenAttributes(pSize, w, h);
    console.log("built screen " + id);
  };

  this.setPalette = function(pal) {
    if (pal.length == 16) {
      for (var i = 0; i < 16; i++)
        palette[i] = pal[i];
    } else
      console.log("error, palettes must contain 16 colors");
  };

  this.returnWidth = function() {
    return screenWidth;
  };

  this.returnHeight = function() {
    return screenHeight;
  };

  this.draw16 = function(str) {
    if (str.length == screenWidth * screenHeight) {
      context.clearRect(0, 0, screenWidth * pixelSize, screenHeight * pixelSize);
      for (var y = 0; y < screenHeight; y++) {
        for (var x = 0; x < screenWidth; x++) {
          switch (str.charAt((y * screenWidth) + x)) {
            case '0':
              context.fillStyle = palette[0];
              break;
            case '1':
              context.fillStyle = palette[1];
              break;
            case '2':
              context.fillStyle = palette[2];
              break;
            case '3':
              context.fillStyle = palette[3];
              break;
            case '4':
              context.fillStyle = palette[4];
              break;
            case '5':
              context.fillStyle = palette[5];
              break;
            case '6':
              context.fillStyle = palette[6];
              break;
            case '7':
              context.fillStyle = palette[7];
              break;
            case '8':
              context.fillStyle = palette[8];
              break;
            case '9':
              context.fillStyle = palette[9];
              break;
            case 'a':
            case 'A':
              context.fillStyle = palette[10];
              break;
            case 'b':
            case 'B':
              context.fillStyle = palette[11];
              break;
            case 'c':
            case 'C':
              context.fillStyle = palette[12];
              break;
            case 'd':
            case 'D':
              context.fillStyle = palette[13];
              break;
            case 'e':
            case 'E':
              context.fillStyle = palette[14];
              break;
            case 'f':
            case 'F':
              context.fillStyle = palette[15];
              break;
            default:
              rgba(255, 0, 0, 0);
              console.log("error, wrong character in string passed to draw16!");
              break;
          }
          context.fillRect(0 + pixelSize * x, 0 + pixelSize * y, pixelSize, pixelSize);
        }
      }
      //console.log("drew to screen");
    } else {
      console.log("incorrect length of string passed into draw16!");
      console.log("length is " + str.length + ", but should be " + (screenWidth * screenHeight) + "!");
    }
  };

  this.buildScreen(id, pSize, w, h); // constructor
}

/* inline-js */
// Palettes to pass to screen
var p0 = ["#000000", "#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF"];
var p1 = ["#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000"];
var p2 = ["#222222", "#333333", "#444444", "#555555", "#666666", "#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111"];
var p3 = ["#333333", "#444444", "#555555", "#666666", "#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222"];
var p4 = ["#444444", "#555555", "#666666", "#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222", "#333333"];
var p5 = ["#555555", "#666666", "#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222", "#333333", "#444444"];
var p6 = ["#666666", "#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222", "#333333", "#444444", "#555555"];
var p7 = ["#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222", "#333333", "#444444", "#555555", "#666666"];
var p8 = ["#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777"];
var p9 = ["#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777", "#888888"];
var pA = ["#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777", "#888888", "#999999"];
var pB = ["#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777", "#888888", "#999999", "#AAAAAA"];
var pC = ["#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB"];
var pD = ["#DDDDDD", "#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC"];
var pE = ["#EEEEEE", "#FFFFFF", "#000000", "#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD"];
var pF = ["#FFFFFF", "#000000", "#111111", "#222222", "#333333", "#444444", "#555555", "#666666", "#777777", "#888888", "#999999", "#AAAAAA", "#BBBBBB", "#CCCCCC", "#DDDDDD", "#EEEEEE"];

var t;
var i = 0;
var running = true;
var command = '(x * y / 2) % 16';
var testStr = "";
var s = new screen("mycanvas", 5, 160, 100);

function drawTest() { // Creates the string
  testStr = "";
  for (var y = 0; y < s.returnHeight(); y++) {
    for (var x = 0; x < s.returnWidth(); x++) {
      switch (parseInt(eval(command))) {
        case 0:
          testStr = testStr.concat('0');
          break;
        case 1:
          testStr = testStr.concat('1');
          break;
        case 2:
          testStr = testStr.concat('2');
          break;
        case 3:
          testStr = testStr.concat('3');
          break;
        case 4:
          testStr = testStr.concat('4');
          break;
        case 5:
          testStr = testStr.concat('5');
          break;
        case 6:
          testStr = testStr.concat('6');
          break;
        case 7:
          testStr = testStr.concat('7');
          break;
        case 8:
          testStr = testStr.concat('8');
          break;
        case 9:
          testStr = testStr.concat('9');
          break;
        case 10:
          testStr = testStr.concat('A');
          break;
        case 11:
          testStr = testStr.concat('B');
          break;
        case 12:
          testStr = testStr.concat('C');
          break;
        case 13:
          testStr = testStr.concat('D');
          break;
        case 14:
          testStr = testStr.concat('E');
          break;
        case 15:
          testStr = testStr.concat('F');
          break;
        default:
          testStr = testStr.concat('X');
          console.log("incorrect entry in testStrPass: " + temp);
          break;
      }
    }
  }
};

function runTest() { // Cycles through palettes
  if (running == true) {
    if (i >= 16) {
      i = 0
    };
    switch (i) {
      case 0:
        s.setPalette(p0);
        break;
      case 1:
        s.setPalette(p1);
        break;
      case 2:
        s.setPalette(p2);
        break;
      case 3:
        s.setPalette(p3);
        break;
      case 4:
        s.setPalette(p4);
        break;
      case 5:
        s.setPalette(p5);
        break;
      case 6:
        s.setPalette(p6);
        break;
      case 7:
        s.setPalette(p7);
        break;
      case 8:
        s.setPalette(p8);
        break;
      case 9:
        s.setPalette(p9);
        break;
      case 10:
        s.setPalette(pA);
        break;
      case 11:
        s.setPalette(pB);
        break;
      case 12:
        s.setPalette(pC);
        break;
      case 13:
        s.setPalette(pD);
        break;
      case 14:
        s.setPalette(pE);
        break;
      case 15:
        s.setPalette(pF);
        break;
    }
    s.draw16(testStr); // Draws to screen
    i++;
    t = setTimeout(runTest, 16);
  }
};

function stop() {
  clearTimeout(t);
  running = false;
};

function restart() {
  if (running == false) {
    running = true;
    runTest();
  }
};

document.getElementById("stopButton").addEventListener("click", function() {
  stop()
});

document.getElementById("restartButton").addEventListener("click", function() {
  restart()
});

document.getElementById("evalButton").addEventListener("click", function() {
  command = document.getElementById('code').value;
  s.setScreenAttributes(document.getElementById('pSize').value, document.getElementById('x').value, document.getElementById('y').value);
  testStr = "";
  drawTest();
  restart()
});

document.addEventListener("DOMContentLoaded", function() {

  drawTest();
  runTest();

});
body{margin-bottom: 50vh;}
<canvas id="mycanvas" style="border: 1px solid #000000"></canvas>
<br />
<button id="stopButton">stop</button>
<button id="restartButton">restart</button>
<br /><br /> pixel size: <input type="text" id="pSize" size="2" value="5" /> x: <input type="text" id="x" size="2" value="160" /> y: <input type="text" id="y" size="2" value="100" />
<br />
<input type="text" id="code" value="(x * y / 2) % 16" /><button id="evalButton">evaluate</button>

由于某种原因,stackoverflow片段说明构造器不正确,但是它可以在Chrome,Firefox,Edge和iOS Safari中使用,所以我不知道它的想法是什么。

0 个答案:

没有答案