General Questions
Hi, I tried to move logic to a process using setTimeout in order to show a loading screen right away and update the page once the process is complete.
Sometimes it kind of works, sometimes it does not. Now I think I need to know some more theory to get to the bottom of this problem.
Is there always a programming error involved when a website blocks the whole browser (Firefox) or everything in a tab (Chrome)?
Can it be a case of leaky abstraction (like a C/C++ game loop that never sleeps and does not allow the CPU to work on other processes)? Do I have to write a mechanism that works with several setTimeouts if the process takes long and has a lot of work to do?
Anything else I need to look into / keep in mind?
Details
I have read https://softwareengineering.stackexchange.com/questions/202047/what-determines-which-javascript-functions-are-blocking-vs-non-blocking and it does not seem to answer the questions.
The problem can be seen here: http://procgames.com/raidaces/
Firefox sometimes is blocked and does not update anything until the whole process is complete (weird, because I render the loading state in the canvas before I call the loading process).
In Chrome the text is blocked (can not be selected) until the process is complete, so I assume the whole Tab is frozen.
What happens is: 25 images (1024x1024) are rendered in canvases and moved to img entities using toDataURL (so the client is pretty busy).
Maybe I am doing something wrong? The program starts in the HTML file:
<div class=container>
<h1>Raid Aces</h1>
<canvas id="gameCanvas" width="800" height="600" onClick="toggleRunning(gameContext)"></canvas>
<div id="debugArea">The Epic Battles Of The Ancient Clans ... or whatever ...</div>
<canvas id="mapCanvas" width="128" height="128"></canvas>
<div class="clear"></div>
<div id="hiddenContentArea"></div>
<script>
var gameCanvas = document.getElementById('gameCanvas');
var gameContext = gameCanvas.getContext('2d');
var hiddenContentArea = document.getElementById('hiddenContentArea');
var mapCanvas = document.getElementById('mapCanvas');
var mapContext = mapCanvas.getContext('2d');
gameContext.beginPath();
gameContext.rect(0, 0, 800, 600);
gameContext.fillStyle = "#88BB88";
gameContext.fill();
gameContext.font = "bold 16px sans-serif";
gameContext.fillStyle = "#FFFFFF";
gameContext.fillText("Loading", 350, 294);
mapContext.beginPath();
mapContext.rect(0, 0, 128, 128);
mapContext.fillStyle = "#88BB88";
mapContext.fill();
mapContext.font = "bold 10px sans-serif";
mapContext.fillStyle = "#FFFFFF";
mapContext.fillText("Loading", 42, 62);
initEngine(gameContext);
initGame(gameContext, hiddenContentArea);
document.addEventListener('keydown', function(event) {
handleInputEvent(event, gameContext);
});
</script>
</div>
which calls initGame ...
function initGame(gameContext, hiddenContentArea) {
if (!engine.isInitialized) {
throw "error_engine_not_initialized";
}
var eventsModule = engine.getModule("events");
log("Rendering Map, please be patient!");
eventsModule.changeGameState(new GameStateLoading(engine));
}
... and this is where the asynchronous call should be realized:
ModuleEvents.prototype.changeGameState = function(moduleGameState) {
var oldGameState = this.gameState;
if (oldGameState) {
oldGameState.uninit();
}
this.gameState = moduleGameState;
var callbackFunction = this.makeCallbackExecution(oldGameState,
this.gameState, this.eventBus);
setTimeout(callbackFunction, 10);
};
ModuleEvents.prototype.makeCallbackExecution = function(oldGameState,
newGameState, eventBus) {
return function() {
newGameState.init();
eventBus
.fireEvent(new EventGameStateChanged(oldGameState, newGameState));
};
};

callbackFunction(which you obtain viathis.makeCallbackExecution(oldGameState, this.gameState, this.eventBus);) works fast? Because if it isn't then there is no sense (almost) in usingsetTimeout: if function executes for n seconds, then UI will be "unresponsive" during these n seconds. So it's important to split jobs in chunks (which isn't easy, by the way).