我已经尝试学习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中使用,所以我不知道它的想法是什么。