2012-10-06 55 views
0

我正在研究大量使用canvas元素的HTML5遊戲。有一個連續的事件循環會更新主要的畫布元素,然後定期對其進行重大更改。基本上,隨着角色移動,背景被更新。發生這種情況時會有明顯的停頓,所以我試圖用異步函數執行操作,但我似乎正在執行完全相同的性能命中。我試過對異步函數中的一個不可見畫布執行所有操作,然後在事件循環完成後將其複製到主畫布中,但同樣沒有提高性能。異步畫布操作干擾JavaScript事件循環。

我寫了這個無意義的小程序,似乎重複了我說的行爲。看起來好像綁定canvas元素,即使在異步函數中,也會影響程序的其餘部分。

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中的迭代次數才能獲得效果。

謝謝!

回答

1

即使使用setTimeout,執行也會鎖定所有內容,直到函數調用完成,這只是Javascript的本質。這實際上比詛咒更加福祉,因爲它大大簡化了事情。

由於Javascript的單線程特性,所謂的「Web Workers」被髮明出來。這在瀏覽器中是一個相對較新的功能,但它允許您執行單獨運行而不鎖定主線程的任務。 In moderna browsers, you can perform canvas tasks using web workers

現在,在不瞭解任何關於遊戲的情況下,應該可以實現您想要實現的目標(更新背景圖形,移動角色等),而無需調用花費很長時間執行的繁重功能。你正在執行每像素操作很多嗎?如果是這樣,他們不能通過其他方式完成嗎?在開始使用Web工作人員之前,我會開始着眼於優化代碼。瞭解。

+0

瞭解。我認爲我可能會抵制這裏的語言的硬限制。 –