I'm currently writing a WebGL HTML5 game, and large part of the game initialization involved loading assets streamed over a websocket, and saving them to disk using the FileSystem API.
As part of optimizing the code, we're trying to eliminate as many memory allocations as we can, which means cutting down on the use of closures, object/array creation during the main game loop and so on.
One of the biggest uses of closures left is our interaction with the FileSystem API, namely the part where we write the assets to disk:
//Write file to disk
directory.getFile(
filename,
CREATE_TRUE,
function(fileEntry) {
fileEntry.createWriter(
function(fileWriter) {
fileWriter.onwriteend=function(e) {
finishedRequest(filename);
if (onSuccess!==undefined) onSuccess(filename);
};
fileWriter.onerror=function(e) {
finishedRequest(filename);
if (onError!==undefined) onError(filename, "Write error: "+directoryRoot+"/"+filename);
};
var dataBlob=new Blob([new Uint8Array(data)]);
if (append) fileWriter.seek(fileWriter.length);
fileWriter.write(dataBlob,"application/octet-stream");
},
function(e) {
finishedRequest(filename);
if (onError!==undefined) onError(filename,"File writer creation error: "+directoryRoot+"/"+filename:"");
}
);
},
function(e) {
finishedRequest(filename);
if (onError!==undefined) onError(filename,DEVELOPMENT_MODE?"File not found: "+directoryRoot+"/"+filename:"");
}
);
As you can see, this code involves the creation of something like six new closures for every file write, which isn't the greatest when we're trying to cut down on memory allocation.
I initially tried to pull each of the closures out into standalone functions, but obviously I then needed to be able to get references to things like the filename and onSuccess callback function from those standalone functions (whereas previously they would have been able to have access to them from their outer closures):
...
fileWriter.onwriteend=onFileWrite;
...
function onFileWrite=function(e) {
finishedRequest(filename); //filename needs to be retrieved from somewhere...
if (onSuccess!==undefined) onSuccess(filename);
}
The problem is that the onFileWrite callback is only supplied with the event object, which contains a reference to the target fileWriter, but nothing higher. Crucially, there seems to be no way to link the fileEntry with the fileWriter that it creates, as the createWriter callback only gets given the FileWriter object - with no meta data about what created it.
My question is this: is it possible to rewrite this without using quite some many closures - or ideally none at all?
Edit: I'm convinced that it is (unfortunately) impossible to do this without creating some kind of container for the details of the request, be it a new function whose closure includes the request details, or a new object whose properties have the details. So, this question really then becomes about the best way to achieve the file write with the smallest amount of memory churn.